diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d517c48 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +# 根目录 .dockerignore(用于 docker-compose 构建上下文) +.git/ +.gitignore +docs/ +tests/ +*.md +*.log +*.txt +.env +.env.* +.pytest_cache/ +__pycache__/ +*.pyc +*.pyo diff --git a/.env.example b/.env.example index 4dc1674..eeed042 100644 --- a/.env.example +++ b/.env.example @@ -1,34 +1,90 @@ -# 数据库 +# ============================================================================= +# GEO 平台环境变量配置模板 +# 复制此文件为 .env 并填入真实值,切勿将 .env 提交到 Git +# ============================================================================= + +# ----------------------------------------------------------------------------- +# 数据库(PostgreSQL) +# ----------------------------------------------------------------------------- DATABASE_URL=postgresql+asyncpg://postgres:postgres123@db:5432/geo_platform -# Redis +# ----------------------------------------------------------------------------- +# Redis(缓存 / 任务队列) +# ----------------------------------------------------------------------------- REDIS_URL=redis://redis:6379/0 -# JWT -JWT_SECRET=your-secret-key-change-in-production +# ----------------------------------------------------------------------------- +# JWT 认证密钥 +# 必须 >= 32 字符,可用以下命令生成: +# python3 -c "import secrets; print(secrets.token_hex(32))" +# ----------------------------------------------------------------------------- +JWT_SECRET=your-jwt-secret-at-least-32-characters-long JWT_EXPIRE_HOURS=24 -# 前端 -NEXT_PUBLIC_API_URL=http://localhost:8000 +# ----------------------------------------------------------------------------- +# NextAuth / 前端 Session 密钥(如使用 NextAuth,必须 >= 32 字符) +# ----------------------------------------------------------------------------- +SECRET_KEY=your-nextauth-secret-at-least-32-characters-long -# Playwright +# ----------------------------------------------------------------------------- +# 前端 & CORS +# ----------------------------------------------------------------------------- +NEXT_PUBLIC_API_URL=http://localhost:8000 +CORS_ORIGINS=http://localhost:3000,http://localhost:3001 + +# ----------------------------------------------------------------------------- +# Playwright(用于 SEO 抓取,Docker 内路径) +# ----------------------------------------------------------------------------- PLAYWRIGHT_BROWSERS_PATH=/ms-playwright -# 国内大模型API(可选) -ZHIPU_API_KEY= -TONGYI_API_KEY= +# ----------------------------------------------------------------------------- +# LLM 功能开关 +# ----------------------------------------------------------------------------- +ENABLE_LLM=true -# ---- LLM Provider 配置 ---- -# 默认LLM提供商: openai | deepseek +# ----------------------------------------------------------------------------- +# LLM Provider 配置 +# 支持: openai | deepseek +# 使用 OpenAI 兼容协议,可对接 DashScope、DeepSeek 等平台 +# ----------------------------------------------------------------------------- DEFAULT_LLM_PROVIDER=openai +DEFAULT_LLM_MODEL=qwen3-coder-plus -# OpenAI -OPENAI_API_KEY= -OPENAI_MODEL=gpt-4o-mini -OPENAI_BASE_URL=https://api.openai.com/v1 +# OpenAI 层配置(百炼 DashScope Coding Plan 优先) +# 百炼 API Key: 癷67 https://bailian.console.aliyun.com/ 申请 +OPENAI_API_KEY=your-dashscope-api-key-here +OPENAI_MODEL=qwen3-coder-plus +OPENAI_BASE_URL=https://coding.dashscope.aliyuncs.com/v1 # DeepSeek -DEEPSEEK_API_KEY= +DEEPSEEK_API_KEY=your-deepseek-api-key-here DEEPSEEK_MODEL=deepseek-chat DEEPSEEK_BASE_URL=https://api.deepseek.com/v1 DEEPSEEK_MAX_CONTEXT=64000 + +# ----------------------------------------------------------------------------- +# 国内 AI 平台 API(可选,按需填写) +# ----------------------------------------------------------------------------- + +# 智谱 AI(ChatGLM 系列) +ZHIPU_API_KEY=your-zhipu-api-key-here + +# 阿里云通义千问 +TONGYI_API_KEY=your-tongyi-api-key-here + +# Kimi(月之暗面) +MOONSHOT_API_KEY=your-moonshot-api-key-here + +# 百度千帆(文心一言) +BAIDU_QIANFAN_API_KEY=your-baidu-qianfan-api-key-here +BAIDU_QIANFAN_SECRET_KEY=your-baidu-qianfan-secret-key-here + +# 豆包(字节跳动) +DOUBAO_API_KEY=your-doubao-api-key-here +DOUBAO_ENDPOINT_ID=your-doubao-endpoint-id-here + +# ----------------------------------------------------------------------------- +# API 调用频率限制 +# ----------------------------------------------------------------------------- +# 每分钟最大请求数(防止触发平台限速) +API_RATE_LIMIT_RPM=10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9cc3c4e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,101 @@ +name: CI Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + # ── 后端 ────────────────────────────────────────────── + backend-lint-test: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: geo_test + ports: ['5432:5432'] + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + redis: + image: redis:7 + ports: ['6379:6379'] + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: | + cd backend + pip install -r requirements.txt + pip install ruff pytest-cov + + - name: Lint (ruff) + run: cd backend && ruff check app/ + + - name: Type check (optional) + run: cd backend && ruff check app/ --select=E,W + continue-on-error: true + + - name: Run tests + env: + DATABASE_URL: postgresql+asyncpg://test:test@localhost:5432/geo_test + REDIS_URL: redis://localhost:6379/0 + JWT_SECRET: test-secret-key-minimum-32-characters-long + ENVIRONMENT: test + run: | + cd backend + pytest tests/ -v --tb=short + + # ── 前端 ────────────────────────────────────────────── + frontend-lint-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + run: cd frontend && npm ci + + - name: Lint (ESLint) + run: cd frontend && npm run lint + + - name: Type check + run: cd frontend && npx tsc --noEmit + + - name: Unit tests + run: cd frontend && npm run test:ci + + # ── Docker build 验证 ────────────────────────────────── + docker-build: + runs-on: ubuntu-latest + needs: [backend-lint-test, frontend-lint-test] + steps: + - uses: actions/checkout@v4 + + - name: Build backend image + run: docker build -t geo-backend:test ./backend + + - name: Build frontend image + run: docker build -t geo-frontend:test ./frontend diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 0000000..425831f --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,99 @@ +name: PR Check + +on: + pull_request: + branches: [main, develop] + types: [opened, synchronize, reopened] + +jobs: + pr-lint-test: + name: Lint & Test (PR) + runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: geo_test + ports: ['5432:5432'] + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + redis: + image: redis:7 + ports: ['6379:6379'] + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # ── 后端检查 ────────────────────────────────── + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install backend dependencies + run: | + cd backend + pip install -r requirements.txt + pip install ruff pytest-cov + + - name: Backend lint + run: cd backend && ruff check app/ + + - name: Backend tests + env: + DATABASE_URL: postgresql+asyncpg://test:test@localhost:5432/geo_test + REDIS_URL: redis://localhost:6379/0 + JWT_SECRET: test-secret-key-minimum-32-characters-long + ENVIRONMENT: test + run: | + cd backend + pytest tests/ -v --tb=short --cov=app --cov-report=xml + + # ── 前端检查 ────────────────────────────────── + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + run: cd frontend && npm ci + + - name: Frontend lint + run: cd frontend && npm run lint + + - name: Frontend type check + run: cd frontend && npx tsc --noEmit + + - name: Frontend unit tests + run: cd frontend && npm run test:ci + + # ── PR 状态注释 ────────────────────────────────── + - name: Comment PR status + if: always() + uses: actions/github-script@v7 + with: + script: | + const { context, github } = require('@actions/github'); + const status = '${{ job.status }}'; + const emoji = status === 'success' ? '✅' : '❌'; + const body = `## CI 检查结果 ${emoji}\n\n**状态**: ${status}\n\n| 检查项 | 状态 |\n|--------|------|\n| 后端 Lint | ${{ steps.Backend lint.outcome || 'N/A' }} |\n| 后端测试 | ${{ steps.Backend tests.outcome || 'N/A' }} |\n| 前端 Lint | ${{ steps.Frontend lint.outcome || 'N/A' }} |\n| 前端测试 | ${{ steps.Frontend unit tests.outcome || 'N/A' }} |`; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); + continue-on-error: true diff --git a/.gitignore b/.gitignore index 326ac6f..4e1e925 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,10 @@ backend/.venv/ # Environment .env +backend/.env frontend/.env.local +# 不忽略 .env.example(供新成员参考) +!.env.example # IDE .idea/ @@ -41,3 +44,14 @@ redis_data/ .npm-cache/ .pytest_cache/ tsconfig.tsbuildinfo + +# Test artifacts +frontend/test-results/ +frontend/playwright-report/ + +# Temp debug files +login_headers.txt +login_resp.json +test_login.js +test_login2.js +testfile2.txt diff --git a/.qoder/repowiki/zh/content/API接口文档/API接口文档.md b/.qoder/repowiki/zh/content/API接口文档/API接口文档.md index 49176b4..b7c433b 100644 --- a/.qoder/repowiki/zh/content/API接口文档/API接口文档.md +++ b/.qoder/repowiki/zh/content/API接口文档/API接口文档.md @@ -9,34 +9,49 @@ - [backend/app/api/reports.py](file://backend/app/api/reports.py) - [backend/app/api/subscriptions.py](file://backend/app/api/subscriptions.py) - [backend/app/api/admin.py](file://backend/app/api/admin.py) +- [backend/app/api/agents.py](file://backend/app/api/agents.py) +- [backend/app/api/analytics.py](file://backend/app/api/analytics.py) +- [backend/app/api/lifecycle.py](file://backend/app/api/lifecycle.py) +- [backend/app/api/knowledge.py](file://backend/app/api/knowledge.py) - [backend/app/api/deps.py](file://backend/app/api/deps.py) - [backend/app/middleware/rate_limit.py](file://backend/app/middleware/rate_limit.py) - [backend/app/schemas/auth.py](file://backend/app/schemas/auth.py) - [backend/app/schemas/query.py](file://backend/app/schemas/query.py) - [backend/app/schemas/citation.py](file://backend/app/schemas/citation.py) - [backend/app/schemas/subscription.py](file://backend/app/schemas/subscription.py) +- [backend/app/schemas/analytics.py](file://backend/app/schemas/analytics.py) +- [backend/app/schemas/lifecycle.py](file://backend/app/schemas/lifecycle.py) +- [backend/app/schemas/knowledge.py](file://backend/app/schemas/knowledge.py) - [backend/app/services/auth.py](file://backend/app/services/auth.py) - [backend/app/services/query.py](file://backend/app/services/query.py) - [backend/app/services/citation.py](file://backend/app/services/citation.py) - [backend/app/services/subscription.py](file://backend/app/services/subscription.py) - [backend/app/services/admin.py](file://backend/app/services/admin.py) +- [backend/app/services/analytics/insights.py](file://backend/app/services/analytics/insights.py) +- [backend/app/services/analytics/tracker.py](file://backend/app/services/analytics/tracker.py) +- [backend/app/services/knowledge/rag_service.py](file://backend/app/services/knowledge/rag_service.py) +- [backend/app/services/knowledge/chunker.py](file://backend/app/services/knowledge/chunker.py) +- [backend/app/services/knowledge/embedder.py](file://backend/app/services/knowledge/embedder.py) +- [backend/app/services/knowledge/retriever.py](file://backend/app/services/knowledge/retriever.py) - [backend/app/config.py](file://backend/app/config.py) - [backend/app/models/user.py](file://backend/app/models/user.py) - [backend/app/models/query.py](file://backend/app/models/query.py) - [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py) - [backend/app/models/query_task.py](file://backend/app/models/query_task.py) - [backend/app/models/subscription.py](file://backend/app/models/subscription.py) +- [backend/app/models/agent.py](file://backend/app/models/agent.py) +- [backend/app/models/lifecycle.py](file://backend/app/models/lifecycle.py) +- [backend/app/models/knowledge.py](file://backend/app/models/knowledge.py) ## 更新摘要 **所做更改** -- 新增订阅管理API模块,包含套餐查询、订阅管理、历史记录等功能 -- 新增管理员API模块,包含系统统计、用户管理、权限控制等功能 -- 新增限流中间件,提供多层级请求限制保护 -- 新增PDF报告导出功能,扩展报告导出格式 -- 更新认证API,新增忘记密码、邮箱验证、密码修改等端点 -- 完善错误处理和状态码说明 -- 更新架构图以反映新增模块 +- 新增代理管理API模块,支持AI Agent的注册、配置管理、任务分发与监控 +- 新增分析监控API模块,提供内容发布追踪、效果指标管理、洞察生成与排行榜功能 +- 新增生命周期管理API模块,支持品牌项目全生命周期管理与阶段进度跟踪 +- 新增知识库API模块,提供知识库CRUD、文档管理、向量化检索与RAG服务 +- 更新架构图以反映新增的四个核心API模块 +- 完善错误处理和状态码说明,新增各模块特有的错误场景 ## 目录 1. [简介](#简介) @@ -50,10 +65,10 @@ 9. [结论](#结论) ## 简介 -本文件为GEO平台的完整API接口文档,涵盖认证、查询管理、引用数据、报告导出、订阅管理和管理员管理等核心功能模块。文档详细记录了所有RESTful API端点的HTTP方法、URL模式、请求参数与响应格式,并说明了JWT令牌管理、用户注册登录、权限验证机制、任务创建与执行、数据查询与统计分析、CSV和PDF格式报告导出流程,以及订阅管理和系统管理功能。 +本文件为GEO平台的完整API接口文档,涵盖认证、查询管理、引用数据、报告导出、订阅管理、管理员管理、代理管理、分析监控、生命周期管理和知识库等核心功能模块。文档详细记录了所有RESTful API端点的HTTP方法、URL模式、请求参数与响应格式,并说明了JWT令牌管理、用户注册登录、权限验证机制、任务创建与执行、数据查询与统计分析、CSV和PDF格式报告导出流程,以及订阅管理、系统管理、AI代理调度、内容分析追踪、项目生命周期管理和智能知识检索功能。 ## 项目结构 -后端采用FastAPI框架,按功能模块组织API路由:认证(/api/v1/auth)、查询词(/api/v1/queries)、引用数据(/api/v1/citations)、报告(/api/v1/reports)、订阅管理(/api/v1/subscriptions)、管理员(/api/v1/admin)。应用启动时初始化数据库模型并启动查询调度器,同时启用CORS允许前端localhost:3000访问,集成限流中间件和请求日志中间件。 +后端采用FastAPI框架,按功能模块组织API路由:认证(/api/v1/auth)、查询词(/api/v1/queries)、引用数据(/api/v1/citations)、报告(/api/v1/reports)、订阅管理(/api/v1/subscriptions)、管理员(/api/v1/admin)、代理管理(/api/v1/agents)、分析监控(/api/v1/analytics)、生命周期管理(/api/v1/lifecycle)、知识库(/api/v1/knowledge)。应用启动时初始化数据库模型并启动查询调度器,同时启用CORS允许前端localhost:3000访问,集成限流中间件和请求日志中间件。 ```mermaid graph TB @@ -63,22 +78,25 @@ A --> D["引用数据路由
backend/app/api/citations.py"] A --> E["报告路由
backend/app/api/reports.py"] A --> F["订阅管理路由
backend/app/api/subscriptions.py"] A --> G["管理员路由
backend/app/api/admin.py"] -A --> H["依赖注入与认证中间件
backend/app/api/deps.py"] -A --> I["限流中间件
backend/app/middleware/rate_limit.py"] -A --> J["配置中心
backend/app/config.py"] -A --> K["数据库模型
backend/app/models/*.py"] -A --> L["业务服务层
backend/app/services/*.py"] -A --> M["数据传输对象
backend/app/schemas/*.py"] +A --> H["代理管理路由
backend/app/api/agents.py"] +A --> I["分析监控路由
backend/app/api/analytics.py"] +A --> J["生命周期管理路由
backend/app/api/lifecycle.py"] +A --> K["知识库路由
backend/app/api/knowledge.py"] +A --> L["依赖注入与认证中间件
backend/app/api/deps.py"] +A --> M["限流中间件
backend/app/middleware/rate_limit.py"] +A --> N["配置中心
backend/app/config.py"] +A --> O["数据库模型
backend/app/models/*.py"] +A --> P["业务服务层
backend/app/services/*.py"] +A --> Q["数据传输对象
backend/app/schemas/*.py"] ``` **图表来源** - [backend/app/main.py:12-78](file://backend/app/main.py#L12-L78) - [backend/app/api/auth.py:30](file://backend/app/api/auth.py#L30) -- [backend/app/api/queries.py:12](file://backend/app/api/queries.py#L12) -- [backend/app/api/citations.py:21](file://backend/app/api/citations.py#L21) -- [backend/app/api/reports.py:15](file://backend/app/api/reports.py#L15) -- [backend/app/api/subscriptions.py:23](file://backend/app/api/subscriptions.py#L23) -- [backend/app/api/admin.py:17](file://backend/app/api/admin.py#L17) +- [backend/app/api/agents.py:29](file://backend/app/api/agents.py#L29) +- [backend/app/api/analytics.py:26](file://backend/app/api/analytics.py#L26) +- [backend/app/api/lifecycle.py:24](file://backend/app/api/lifecycle.py#L24) +- [backend/app/api/knowledge.py:38](file://backend/app/api/knowledge.py#L38) **章节来源** - [backend/app/main.py:1-84](file://backend/app/main.py#L1-L84) @@ -91,22 +109,29 @@ A --> M["数据传输对象
backend/app/schemas/*.py"] - 报告导出:支持CSV和PDF格式导出指定查询的引用记录。 - 订阅管理:提供套餐查询、订阅创建、取消订阅、历史记录查看等功能,支持多层级权限控制。 - 管理员管理:提供系统统计、用户管理、权限控制、计划更新等后台管理功能。 -- 数据模型与服务:用户、查询、引用记录、查询任务、订阅等模型及对应的服务逻辑。 +- 代理管理:支持AI Agent的注册、配置管理、任务分发与监控,提供任务创建、状态查询、日志查看和取消功能。 +- 分析监控:提供内容发布追踪、效果指标管理、洞察生成与排行榜功能,支持组织级别的数据分析。 +- 生命周期管理:支持品牌项目的全生命周期管理,包括项目快速启动、阶段进度跟踪、时间线事件和统计分析。 +- 知识库管理:提供知识库CRUD、文档管理、向量化检索与RAG服务,支持多种文档源和智能搜索。 +- 数据模型与服务:用户、查询、引用记录、查询任务、订阅、代理、分析、生命周期、知识库等模型及对应的服务逻辑。 **章节来源** - [backend/app/main.py:39-84](file://backend/app/main.py#L39-L84) - [backend/app/api/auth.py:33-115](file://backend/app/api/auth.py#L33-L115) -- [backend/app/api/subscriptions.py:26-77](file://backend/app/api/subscriptions.py#L26-L77) -- [backend/app/api/admin.py:29-108](file://backend/app/api/admin.py#L29-L108) +- [backend/app/api/agents.py:66-299](file://backend/app/api/agents.py#L66-L299) +- [backend/app/api/analytics.py:47-243](file://backend/app/api/analytics.py#L47-L243) +- [backend/app/api/lifecycle.py:85-297](file://backend/app/api/lifecycle.py#L85-L297) +- [backend/app/api/knowledge.py:81-502](file://backend/app/api/knowledge.py#L81-L502) - [backend/app/middleware/rate_limit.py:10-83](file://backend/app/middleware/rate_limit.py#L10-L83) ## 架构概览 -下图展示了客户端与后端各模块之间的交互关系,包括认证流程、查询管理、引用数据处理、报告导出、订阅管理和管理员管理。 +下图展示了客户端与后端各模块之间的交互关系,包括认证流程、查询管理、引用数据处理、报告导出、订阅管理、管理员管理、代理调度、分析监控、生命周期管理和知识库检索。 ```mermaid graph TB subgraph "客户端" FE["前端应用
localhost:3000"] +ENDUSER["终端用户"] end subgraph "后端服务" AUTH["认证模块
/api/v1/auth"] @@ -115,6 +140,10 @@ CITATIONS["引用数据模块
/api/v1/citations"] REPORTS["报告模块
/api/v1/reports"] SUBSCRIPTIONS["订阅管理模块
/api/v1/subscriptions"] ADMIN["管理员模块
/api/v1/admin"] +AGENTS["代理管理模块
/api/v1/agents"] +ANALYTICS["分析监控模块
/api/v1/analytics"] +LIFECYCLE["生命周期管理模块
/api/v1/lifecycle"] +KNOWLEDGE["知识库模块
/api/v1/knowledge"] DEPS["依赖注入与认证中间件"] RATELIMIT["限流中间件"] LOGGING["请求日志中间件"] @@ -128,30 +157,54 @@ FE --> CITATIONS FE --> REPORTS FE --> SUBSCRIPTIONS FE --> ADMIN +FE --> AGENTS +FE --> ANALYTICS +FE --> LIFECYCLE +FE --> KNOWLEDGE +ENDUSER --> AGENTS +ENDUSER --> ANALYTICS +ENDUSER --> LIFECYCLE +ENDUSER --> KNOWLEDGE AUTH --> DEPS QUERIES --> DEPS CITATIONS --> DEPS REPORTS --> DEPS SUBSCRIPTIONS --> DEPS ADMIN --> DEPS +AGENTS --> DEPS +ANALYTICS --> DEPS +LIFECYCLE --> DEPS +KNOWLEDGE --> DEPS AUTH --> RATELIMIT QUERIES --> RATELIMIT CITATIONS --> RATELIMIT REPORTS --> RATELIMIT SUBSCRIPTIONS --> RATELIMIT ADMIN --> RATELIMIT +AGENTS --> RATELIMIT +ANALYTICS --> RATELIMIT +LIFECYCLE --> RATELIMIT +KNOWLEDGE --> RATELIMIT AUTH --> LOGGING QUERIES --> LOGGING CITATIONS --> LOGGING REPORTS --> LOGGING SUBSCRIPTIONS --> LOGGING ADMIN --> LOGGING +AGENTS --> LOGGING +ANALYTICS --> LOGGING +LIFECYCLE --> LOGGING +KNOWLEDGE --> LOGGING AUTH --> SERVICES QUERIES --> SERVICES CITATIONS --> SERVICES REPORTS --> SERVICES SUBSCRIPTIONS --> SERVICES ADMIN --> SERVICES +AGENTS --> SERVICES +ANALYTICS --> SERVICES +LIFECYCLE --> SERVICES +KNOWLEDGE --> SERVICES SERVICES --> MODELS MODELS --> CONFIG ``` @@ -450,6 +503,208 @@ AdminAPI-->>Admin : 200 用户列表 - [backend/app/api/admin.py:29-108](file://backend/app/api/admin.py#L29-L108) - [backend/app/services/admin.py:14-188](file://backend/app/services/admin.py#L14-L188) +### 代理管理接口 +- 接口前缀:/api/v1/agents +- 路由与功能: + - GET /:列出所有Agent,支持按类型和状态筛选 + - GET /{agent_name}:获取Agent详情 + - GET /{agent_name}/config:获取Agent配置 + - PUT /{agent_name}/config:更新Agent配置 + - GET /tasks/:列出任务,支持按Agent、状态、类型筛选 + - POST /tasks/:创建任务(分发给Agent),支持优先级、回调URL、超时设置 + - GET /tasks/{task_id}:获取任务状态 + - POST /tasks/{task_id}/cancel:取消任务 + - GET /tasks/{task_id}/logs:获取任务日志 +- 权限与限制: + - 需要登录用户权限 + - 任务分发需要有效的Agent名称和配置 +- 请求参数与响应格式: + - Agent列表:items数组与total总数 + - Agent详情:包含名称、类型、状态、描述、版本、端点、能力等 + - 配置更新:返回更新的键列表和成功消息 + - 任务创建:返回任务ID、初始状态和成功消息 + - 任务状态:包含状态、错误消息、开始/完成时间等 + - 任务日志:包含日志级别、消息、元数据和时间戳 +- 错误处理: + - Agent不存在返回404 + - 任务不存在返回404 + - 任务分发错误返回400 + - 参数校验失败返回422 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AgentsAPI as "代理管理API" +participant Dispatcher as "任务调度器" +participant Registry as "Agent注册表" +participant DB as "数据库" +Client->>AgentsAPI : POST /api/v1/agents/tasks/ +AgentsAPI->>Dispatcher : 创建任务消息 +Dispatcher->>Registry : 查找可用Agent +Registry-->>Dispatcher : Agent信息 +Dispatcher->>DB : 存储任务记录 +DB-->>Dispatcher : 任务ID +Dispatcher-->>AgentsAPI : 任务ID与状态 +AgentsAPI-->>Client : 201 任务信息 +``` + +**图表来源** +- [backend/app/api/agents.py:186-222](file://backend/app/api/agents.py#L186-L222) +- [backend/app/models/agent.py:98-155](file://backend/app/models/agent.py#L98-L155) + +**章节来源** +- [backend/app/api/agents.py:66-299](file://backend/app/api/agents.py#L66-L299) +- [backend/app/models/agent.py:12-206](file://backend/app/models/agent.py#L12-L206) + +### 分析监控接口 +- 接口前缀:/api/v1/analytics +- 路由与功能: + - POST /publish:记录内容发布,支持内容标题、ID、平台、URL、状态、发布时间 + - PUT /metrics/{publish_id}:更新内容效果指标(追加快照),支持浏览量、点赞数、评论数、分享数、书签数、AI引用数、搜索展示量、搜索点击量、平均阅读时长、阅读完成率 + - GET /overview:获取全局效果概览,包含发布总数、总浏览量、总互动数、总AI引用数、平均参与率、平台分布 + - GET /content/{publish_id}:获取单条内容详细表现 + - GET /top:获取表现最好内容排行,支持按浏览量、点赞数、评论数、分享数、AI引用数、阅读完成率排序 + - GET /insights:获取洞察列表,支持限制数量和类型筛选 + - POST /insights/generate:触发AI生成洞察建议 + - POST /insights/{insight_id}/apply:标记洞察已应用 +- 权限与限制: + - 需要用户关联组织权限 + - 发布记录必须属于当前组织 +- 请求参数与响应格式: + - 发布记录:包含组织ID、内容标题、内容ID、平台、URL、状态、发布时间、创建时间 + - 指标更新:返回更新后的指标快照 + - 全局概览:包含统计指标和平台分布 + - 内容表现:包含最新指标和历史指标列表 + - 洞察列表:包含洞察ID、类型、标题、描述、建议、严重程度、应用状态 +- 错误处理: + - 用户未关联组织返回403 + - 发布记录不存在或无权限返回404 + - 参数校验失败返回422 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AnalyticsAPI as "分析监控API" +participant Tracker as "分析追踪器" +participant Generator as "洞察生成器" +participant DB as "数据库" +Client->>AnalyticsAPI : POST /api/v1/analytics/publish +AnalyticsAPI->>Tracker : 记录发布 +Tracker->>DB : 存储发布记录 +DB-->>Tracker : 发布ID +Tracker-->>AnalyticsAPI : 发布记录 +AnalyticsAPI-->>Client : 201 发布记录 +Client->>AnalyticsAPI : POST /api/v1/analytics/insights/generate +AnalyticsAPI->>Generator : 生成洞察 +Generator->>DB : 查询数据分析 +DB-->>Generator : 分析结果 +Generator-->>AnalyticsAPI : 洞察建议 +AnalyticsAPI-->>Client : 洞察列表 +``` + +**图表来源** +- [backend/app/api/analytics.py:47-60](file://backend/app/api/analytics.py#L47-L60) +- [backend/app/api/analytics.py:206-212](file://backend/app/api/analytics.py#L206-L212) + +**章节来源** +- [backend/app/api/analytics.py:47-243](file://backend/app/api/analytics.py#L47-L243) +- [backend/app/schemas/analytics.py:14-145](file://backend/app/schemas/analytics.py#L14-L145) +- [backend/app/services/analytics/insights.py](file://backend/app/services/analytics/insights.py) +- [backend/app/services/analytics/tracker.py](file://backend/app/services/analytics/tracker.py) + +### 生命周期管理接口 +- 接口前缀:/api/v1/lifecycle +- 路由与功能: + - GET /projects/stats:获取项目统计信息,包含项目总数、活跃项目数、阶段分布、完成率 + - GET /projects/{project_id}/timeline:获取项目时间线事件,包含创建事件和各阶段开始/完成事件 + - POST /projects/quick-start:项目快速启动,创建品牌基建阶段的项目 + - GET /projects/{project_id}/stages:获取项目阶段列表 + - PUT /projects/{project_id}/stages/{stage_number}:更新项目阶段状态,支持开始时间、完成时间、备注、指标 +- 权限与限制: + - 需要用户关联组织权限 + - 项目必须属于当前组织 +- 请求参数与响应格式: + - 项目统计:包含总数、活跃数、阶段分布、完成率 + - 时间线事件:包含事件类型、描述、时间戳、阶段编号 + - 项目创建:返回创建的项目和成功消息 + - 阶段更新:返回更新后的阶段详情 +- 错误处理: + - 用户未关联组织返回404 + - 项目不存在返回404 + - 阶段不存在返回404 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant LifecycleAPI as "生命周期API" +participant DB as "数据库" +Client->>LifecycleAPI : POST /api/v1/lifecycle/projects/quick-start +LifecycleAPI->>DB : 创建组织如不存在 +DB-->>LifecycleAPI : 组织ID +LifecycleAPI->>DB : 创建项目 +DB-->>LifecycleAPI : 项目ID +LifecycleAPI->>DB : 创建5个阶段 +DB-->>LifecycleAPI : 阶段列表 +LifecycleAPI-->>Client : 201 项目详情 +``` + +**图表来源** +- [backend/app/api/lifecycle.py:190-230](file://backend/app/api/lifecycle.py#L190-L230) + +**章节来源** +- [backend/app/api/lifecycle.py:85-297](file://backend/app/api/lifecycle.py#L85-L297) +- [backend/app/schemas/lifecycle.py:9-68](file://backend/app/schemas/lifecycle.py#L9-L68) +- [backend/app/models/lifecycle.py:12-92](file://backend/app/models/lifecycle.py#L12-L92) + +### 知识库接口 +- 接口前缀:/api/v1/knowledge +- 路由与功能: + - POST /bases:创建知识库,支持名称、类型、描述 + - GET /bases:列出知识库,支持按类型筛选 + - GET /bases/{kb_id}:获取知识库详情 + - DELETE /bases/{kb_id}:删除知识库(级联删除文档和块) + - POST /bases/{kb_id}/documents:上传文档,支持文本、URL、Markdown源 + - GET /bases/{kb_id}/documents:列出文档 + - DELETE /bases/{kb_id}/documents/{doc_id}:删除文档(级联删除块) + - GET /bases/{kb_id}/documents/{doc_id}/chunks:预览文档块 + - POST /search:知识库搜索,支持查询、知识库ID列表、返回数量 +- 权限与限制: + - 需要用户关联组织权限 + - 文档上传需要有效的知识库ID +- 请求参数与响应格式: + - 知识库创建:返回知识库ID、名称、类型、描述、文档数量、状态、创建时间 + - 文档上传:返回文档ID、标题、源类型、URL、块数量、状态、错误消息、创建时间 + - 搜索结果:包含块ID、内容、分数、文档ID、标题、元数据 +- 错误处理: + - 用户未关联组织返回400 + - 知识库不存在返回404 + - 文档不存在返回404 + - URL内容获取失败返回400 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant KnowledgeAPI as "知识库API" +participant RAGService as "RAG服务" +participant DB as "数据库" +Client->>KnowledgeAPI : POST /api/v1/knowledge/search +KnowledgeAPI->>RAGService : 执行向量搜索 +RAGService->>DB : 查询相似文档 +DB-->>RAGService : 匹配结果 +RAGService-->>KnowledgeAPI : 搜索结果 +KnowledgeAPI->>DB : 记录搜索日志 +DB-->>KnowledgeAPI : 日志ID +KnowledgeAPI-->>Client : 200 搜索结果 +``` + +**图表来源** +- [backend/app/api/knowledge.py:424-501](file://backend/app/api/knowledge.py#L424-L501) + +**章节来源** +- [backend/app/api/knowledge.py:81-502](file://backend/app/api/knowledge.py#L81-L502) +- [backend/app/schemas/knowledge.py:9-77](file://backend/app/schemas/knowledge.py#L9-L77) +- [backend/app/models/knowledge.py:22-213](file://backend/app/models/knowledge.py#L22-L213) + ### 限流中间件 - 功能特性: - 基于内存的简易限流中间件,无需Redis依赖 @@ -503,12 +758,19 @@ PassThrough --> Next - User与Subscription一对多,级联删除 - Query与CitationRecord、QueryTask一对多,级联删除 - CitationRecord外键关联Query + - AgentRegistry与AgentConfig、AgentTask、AgentTaskLog一对多,级联删除 + - LifecycleProject与ProjectStage一对多,级联删除 + - KnowledgeBase与KnowledgeDocument、KnowledgeChunk一对多,级联删除 - 服务层职责: - 认证服务:密码哈希、JWT签发与校验、用户注册与登录、密码重置、邮箱验证 - 查询服务:分页查询、创建/更新/删除、频率与下次查询时间计算 - 引用服务:引用记录查询、统计分析、立即执行任务、CSV和PDF导出 - 订阅服务:套餐管理、订阅创建与取消、历史记录查询 - 管理员服务:系统统计、用户管理、权限控制、计划更新 + - 代理服务:Agent注册表管理、任务调度、配置管理、日志记录 + - 分析服务:发布追踪、指标管理、洞察生成、排行榜计算 + - 生命周期服务:项目管理、阶段跟踪、统计分析 + - 知识库服务:文档管理、向量化处理、RAG检索、搜索日志 ```mermaid classDiagram @@ -554,13 +816,19 @@ class CitationRecord { } class QueryTask { +UUID id -+UUID query_id -+string platform ++UUID agent_id ++string task_type +string status ++int priority ++dict input_data ++dict output_data +string error_message ++UUID organization_id ++UUID project_id +datetime scheduled_at +datetime started_at +datetime completed_at ++datetime created_at } class Subscription { +UUID id @@ -573,12 +841,106 @@ class Subscription { +string payment_method +datetime created_at } +class AgentRegistry { ++UUID id ++string name ++string display_name ++string agent_type ++string description ++string version ++string endpoint ++string status ++dict capabilities ++datetime last_heartbeat ++datetime created_at ++datetime updated_at +} +class AgentTask { ++UUID id ++UUID agent_id ++string task_type ++string status ++int priority ++dict input_data ++dict output_data ++string error_message ++UUID organization_id ++UUID project_id ++datetime scheduled_at ++datetime started_at ++datetime completed_at ++datetime created_at +} +class LifecycleProject { ++UUID id ++UUID organization_id ++string brand_name ++list brand_aliases ++int current_stage ++string status ++UUID created_by ++datetime created_at ++datetime updated_at +} +class ProjectStage { ++UUID id ++UUID project_id ++int stage_number ++string status ++datetime started_at ++datetime completed_at ++string notes ++dict metrics +} +class KnowledgeBase { ++UUID id ++UUID organization_id ++string name ++string type ++string description ++int document_count ++string status ++UUID created_by ++datetime created_at ++datetime updated_at +} +class KnowledgeDocument { ++UUID id ++UUID knowledge_base_id ++string title ++string source_type ++string source_url ++string content ++string content_hash ++int chunk_count ++string status ++string error_message ++dict extra_metadata ++datetime created_at ++datetime updated_at +} +class KnowledgeChunk { ++UUID id ++UUID document_id ++string content ++Vector embedding ++int chunk_index ++int token_count ++dict extra_metadata ++datetime created_at +} User "1" --> "many" Query : "拥有" User "1" --> "many" Subscription : "订阅" +User "1" --> "many" AgentTask : "创建" Query "1" --> "many" CitationRecord : "产生" Query "1" --> "many" QueryTask : "触发任务" CitationRecord "many" --> "1" Query : "属于" Subscription "many" --> "1" User : "属于" +AgentRegistry "1" --> "many" AgentTask : "执行" +AgentTask "many" --> "1" AgentRegistry : "属于" +LifecycleProject "1" --> "many" ProjectStage : "包含" +KnowledgeBase "1" --> "many" KnowledgeDocument : "包含" +KnowledgeDocument "1" --> "many" KnowledgeChunk : "包含" ``` **图表来源** @@ -587,6 +949,9 @@ Subscription "many" --> "1" User : "属于" - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) +- [backend/app/models/agent.py:12-206](file://backend/app/models/agent.py#L12-L206) +- [backend/app/models/lifecycle.py:12-92](file://backend/app/models/lifecycle.py#L12-L92) +- [backend/app/models/knowledge.py:22-213](file://backend/app/models/knowledge.py#L22-L213) **章节来源** - [backend/app/api/deps.py:16-42](file://backend/app/api/deps.py#L16-L42) @@ -603,6 +968,9 @@ Subscription "many" --> "1" User : "属于" - 批量操作:任务创建采用批量插入,减少事务开销。 - 限流保护:多层级限流中间件防止恶意请求和滥用,保护系统稳定性。 - PDF生成:PDF导出使用FPDF库,支持中文字体加载,提供完整的品牌曝光度分析报告。 +- 向量检索:知识库模块使用pgvector扩展进行高效相似性搜索,支持大规模文档向量化处理。 +- 代理调度:Agent任务采用Redis队列进行异步处理,支持高并发任务分发与监控。 +- 分析追踪:分析模块使用专门的追踪器和洞察生成器,优化大数据量的统计分析性能。 ## 故障排除指南 - 认证相关 @@ -625,6 +993,24 @@ Subscription "many" --> "1" User : "属于" - 管理员功能 - 403 非管理员权限:确认当前用户具有管理员权限(is_admin=true)。 - 404 用户不存在:确认用户ID是否有效。 +- 代理管理 + - 404 Agent不存在:确认Agent名称是否正确。 + - 404 任务不存在:确认任务ID格式和权限。 + - 400 任务分发错误:检查Agent配置和可用性。 + - 422 参数校验失败:检查请求体格式和字段约束。 +- 分析监控 + - 403 用户未关联组织:确认用户已加入有效组织。 + - 404 发布记录不存在或无权限:检查发布ID和组织权限。 + - 422 指标更新失败:检查数值范围和字段类型。 +- 生命周期管理 + - 404 用户未关联组织:确认用户已创建或加入组织。 + - 404 项目不存在:检查项目ID和组织归属。 + - 404 阶段不存在:检查阶段编号和项目归属。 +- 知识库管理 + - 400 用户未关联组织:确认用户已加入组织。 + - 404 知识库不存在:检查知识库ID和组织权限。 + - 404 文档不存在:检查文档ID和知识库归属。 + - 400 URL内容获取失败:检查URL可访问性和内容格式。 - 限流保护 - 429 请求过于频繁:检查是否超过限流阈值,等待冷却时间后重试。 - 429 查询执行过于频繁:确认查询执行频率是否超过每小时10次限制。 @@ -636,7 +1022,11 @@ Subscription "many" --> "1" User : "属于" - [backend/app/api/reports.py:25-29](file://backend/app/api/reports.py#L25-L29) - [backend/app/api/subscriptions.py:53-57](file://backend/app/api/subscriptions.py#L53-L57) - [backend/app/api/admin.py:22-25](file://backend/app/api/admin.py#L22-L25) +- [backend/app/api/agents.py:84-88](file://backend/app/api/agents.py#L84-L88) +- [backend/app/api/analytics.py:36-40](file://backend/app/api/analytics.py#L36-L40) +- [backend/app/api/lifecycle.py:146](file://backend/app/api/lifecycle.py#L146) +- [backend/app/api/knowledge.py:92-96](file://backend/app/api/knowledge.py#L92-L96) - [backend/app/middleware/rate_limit.py:47-49](file://backend/app/middleware/rate_limit.py#L47-L49) ## 结论 -GEO平台API采用清晰的模块化设计,围绕用户、查询、引用、报告、订阅与管理六大领域构建RESTful接口。通过JWT认证与严格的资源所有权校验,保障了数据安全;通过统计分析与CSV/PDF导出,满足了业务洞察与合规需求;通过订阅管理和管理员功能,提供了完整的商业运营支持;通过多层级限流中间件,确保了系统的稳定性和安全性。建议在生产环境中进一步完善错误日志、监控指标与缓存策略,持续优化查询性能与用户体验。 \ No newline at end of file +GEO平台API采用清晰的模块化设计,围绕用户、查询、引用、报告、订阅、管理、代理、分析、生命周期和知识库十大领域构建RESTful接口。通过JWT认证与严格的资源所有权校验,保障了数据安全;通过统计分析与CSV/PDF导出,满足了业务洞察与合规需求;通过订阅管理、管理员功能、AI代理调度、内容分析追踪、项目生命周期管理和智能知识检索,提供了完整的商业运营支持;通过多层级限流中间件,确保了系统的稳定性和安全性。新增的四个核心API模块显著增强了平台的智能化水平,包括AI代理的自动化任务处理能力、深度的内容分析与优化建议、完整的项目生命周期管理以及强大的智能知识检索功能。建议在生产环境中进一步完善错误日志、监控指标与缓存策略,持续优化查询性能与用户体验。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端系统架构/前端系统架构.md b/.qoder/repowiki/zh/content/前端系统架构/前端系统架构.md index 668136e..14fc302 100644 --- a/.qoder/repowiki/zh/content/前端系统架构/前端系统架构.md +++ b/.qoder/repowiki/zh/content/前端系统架构/前端系统架构.md @@ -25,16 +25,24 @@ - [components/layout/sidebar.tsx](file://frontend/components/layout/sidebar.tsx) - [components/ui/tabs.tsx](file://frontend/components/ui/tabs.tsx) - [app/api/auth/[...nextauth]/route.ts](file://frontend/app/api/auth/[...nextauth]/route.ts) +- [playwright.config.ts](file://frontend/playwright.config.ts) +- [e2e/tests/dashboard-health.spec.ts](file://frontend/e2e/tests/dashboard-health.spec.ts) +- [e2e/tests/login.spec.ts](file://frontend/e2e/tests/login.spec.ts) +- [e2e/pages/dashboard.page.ts](file://frontend/e2e/pages/dashboard.page.ts) +- [e2e/pages/login.page.ts](file://frontend/e2e/pages/login.page.ts) +- [components/business/index.ts](file://frontend/components/business/index.ts) +- [components/business/agent-status-card.tsx](file://frontend/components/business/agent-status-card.tsx) +- [components/business/alert-card.tsx](file://frontend/components/business/alert-card.tsx) +- [components/dashboard/index.ts](file://frontend/components/dashboard/index.ts) ## 更新摘要 **所做变更** -- 新增认证页面体系:忘记密码、重置密码、邮箱验证、注册页面 -- 新增管理员仪表板页面,支持用户管理和系统统计 -- 新增设置页面重构,采用标签页布局管理个人资料、密码修改和订阅管理 -- 新增API客户端增强,支持完整认证端点(注册、忘记密码、重置密码、邮箱验证、密码修改、个人资料更新) -- 新增认证状态管理,支持管理员权限和会话状态扩展 -- 更新组件结构,新增Tabs组件和增强的侧边栏导航 +- 新增E2E测试框架:引入Playwright测试套件,包含登录页面测试、健康状态Dashboard测试、响应式设计测试 +- 新增业务组件库:扩展GEO特定业务组件,包括Agent状态卡片、告警卡片、指标卡片等 +- 新增仪表板布局重构:改进侧边导航结构,支持固定侧边栏和头部导航 +- 新增测试脚本:添加E2E测试命令,支持多浏览器测试和并行执行 +- 新增业务组件索引:提供统一的业务组件导出接口 ## 目录 1. [引言](#引言) @@ -42,15 +50,19 @@ 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) -6. [依赖分析](#依赖分析) -7. [性能考虑](#性能考虑) -8. [故障排除指南](#故障排除指南) -9. [结论](#结论) -10. [附录](#附录) +6. [E2E测试框架](#e2e测试框架) +7. [业务组件库](#业务组件库) +8. [依赖分析](#依赖分析) +9. [性能考虑](#性能考虑) +10. [故障排除指南](#故障排除指南) +11. [结论](#结论) +12. [附录](#附录) ## 引言 本文件为 GEO 前端系统的架构文档,聚焦于基于 Next.js 14 的应用架构设计,涵盖 App Router 页面组织、服务器组件与客户端组件的混合使用模式;认证系统(NextAuth.js 集成、会话管理与路由保护);UI 组件库设计理念与复用策略;数据获取与状态管理;错误处理机制;以及响应式设计、可访问性与性能优化等最佳实践。 +**更新** 新增E2E测试框架集成、业务组件库扩展、仪表板布局重构等前端架构变化。 + ## 项目结构 前端采用 Next.js 14 App Router 结构,页面按功能域分组(通过路由组 `(auth)` 和 `(dashboard)` 实现),根布局统一注入全局样式与 Provider,认证相关 API 路由集中于 `/api/auth/[...nextauth]`。系统现已扩展为完整的认证体系,包含登录、注册、忘记密码、重置密码、邮箱验证等页面,以及管理员仪表板和设置页面。 @@ -72,13 +84,19 @@ A --> O["tailwind.config.ts
Tailwind 配置"] A --> P["next.config.mjs
Next 配置"] Q["components/layout/sidebar.tsx
侧边栏导航"] --> D R["components/ui/tabs.tsx
标签页组件"] --> M +S["e2e/ 目录
E2E测试框架"] --> T["playwright.config.ts
测试配置"] +S --> U["e2e/tests/ 目录
测试用例"] +S --> V["e2e/pages/ 目录
页面对象"] +W["components/business/ 目录
业务组件库"] --> X["agent-status-card.tsx
代理状态卡片"] +W --> Y["alert-card.tsx
告警卡片"] +W --> Z["metric-card.tsx
指标卡片"] ``` **图表来源** - [app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [app/(auth)/layout.tsx](file://frontend/app/(auth)/layout.tsx#L1-L12) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [app/(auth)/login/page.tsx](file://frontend/app/(auth)/login/page.tsx#L1-L93) - [app/(auth)/register/page.tsx](file://frontend/app/(auth)/register/page.tsx#L1-L128) - [app/(auth)/forgot-password/page.tsx](file://frontend/app/(auth)/forgot-password/page.tsx#L1-L101) @@ -90,22 +108,24 @@ R["components/ui/tabs.tsx
标签页组件"] --> M - [components/layout/sidebar.tsx:1-63](file://frontend/components/layout/sidebar.tsx#L1-L63) - [components/ui/tabs.tsx:1-56](file://frontend/components/ui/tabs.tsx#L1-L56) - [app/api/auth/[...nextauth]/route.ts](file://frontend/app/api/auth/[...nextauth]/route.ts#L1-L7) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) - [next.config.mjs:1-5](file://frontend/next.config.mjs#L1-L5) +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) +- [components/business/index.ts:1-29](file://frontend/components/business/index.ts#L1-L29) **章节来源** - [app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [app/(auth)/layout.tsx](file://frontend/app/(auth)/layout.tsx#L1-L12) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) - [next.config.mjs:1-5](file://frontend/next.config.mjs#L1-L5) ## 核心组件 - 根布局与全局样式:定义站点元数据、字体变量与全局样式入口,并包裹应用上下文 Provider。 - 会话提供者:在客户端注入 SessionProvider,使整个应用可访问 NextAuth 会话状态。 - 认证路由组:提供登录/注册/忘记密码/重置密码/邮箱验证等认证页面的统一容器样式。 -- 仪表盘路由组:提供侧边栏与头部导航,同时在服务器端校验会话,未登录则重定向至登录页。 +- 仪表盘路由组:提供侧边栏与头部导航,支持固定布局和活动状态跟踪,未登录则重定向至登录页。 - 认证配置:NextAuth 选项,使用凭据提供者对接后端认证接口,JWT 会话策略,回调处理 token 与 session 映射,支持管理员权限。 - 类型扩展:为 NextAuth 的 Session 与 JWT 扩展自定义字段,确保类型安全,包含管理员标识。 - API 客户端:封装带鉴权头的通用请求方法,统一错误处理与响应解析,支持完整认证端点。 @@ -117,7 +137,7 @@ R["components/ui/tabs.tsx
标签页组件"] --> M - [app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [app/(auth)/layout.tsx](file://frontend/app/(auth)/layout.tsx#L1-L12) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [lib/auth.ts:1-73](file://frontend/lib/auth.ts#L1-L73) - [types/next-auth.d.ts:1-29](file://frontend/types/next-auth.d.ts#L1-L29) - [lib/api.ts:1-154](file://frontend/lib/api.ts#L1-L154) @@ -151,6 +171,8 @@ AH["NextAuth 路由
app/api/auth/[...nextauth]/route.ts"] UI["UI 组件库
components/ui/*"] LH["头部组件
components/layout/header.tsx"] LS["侧边栏组件
components/layout/sidebar.tsx"] +BC["业务组件库
components/business/*"] +DP["Dashboard组件
components/dashboard/*"] end subgraph "认证服务" NA["NextAuth 服务
lib/auth.ts"] @@ -159,6 +181,13 @@ subgraph "后端 API" API["业务 API 客户端
lib/api.ts"] BE["后端服务
backend/app/*"] end +subgraph "E2E测试框架" +PW["Playwright
playwright.config.ts"] +DS["Dashboard测试
e2e/tests/dashboard-health.spec.ts"] +LSpec["登录测试
e2e/tests/login.spec.ts"] +DPg["Dashboard页面
e2e/pages/dashboard.page.ts"] +LPg["Login页面
e2e/pages/login.page.ts"] +end U --> RL RL --> PR PR --> AL @@ -181,13 +210,17 @@ ADMIN --> API SETTINGS --> API NA --> BE API --> BE +PW --> DS +PW --> LSpec +DS --> DPg +LSpec --> LPg ``` **图表来源** - [app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [app/(auth)/layout.tsx](file://frontend/app/(auth)/layout.tsx#L1-L12) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [app/(auth)/login/page.tsx](file://frontend/app/(auth)/login/page.tsx#L1-L93) - [app/(auth)/register/page.tsx](file://frontend/app/(auth)/register/page.tsx#L1-L128) - [app/(auth)/forgot-password/page.tsx](file://frontend/app/(auth)/forgot-password/page.tsx#L1-L101) @@ -201,6 +234,9 @@ API --> BE - [app/api/auth/[...nextauth]/route.ts](file://frontend/app/api/auth/[...nextauth]/route.ts#L1-L7) - [lib/auth.ts:1-73](file://frontend/lib/auth.ts#L1-L73) - [lib/api.ts:1-154](file://frontend/lib/api.ts#L1-L154) +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) +- [e2e/tests/dashboard-health.spec.ts:1-264](file://frontend/e2e/tests/dashboard-health.spec.ts#L1-L264) +- [e2e/tests/login.spec.ts:1-126](file://frontend/e2e/tests/login.spec.ts#L1-L126) ## 详细组件分析 @@ -208,7 +244,7 @@ API --> BE - 凭据提供者:使用邮箱/密码进行认证,调用后端登录接口,成功后返回包含用户信息与访问令牌的对象,支持管理员权限标识。 - JWT 会话策略:在回调中将访问令牌与用户 ID 写入 JWT,并在 session 回调中回填到 session 对象,包含 is_admin 字段。 - 完整认证流程:支持注册、登录、忘记密码、重置密码、邮箱验证、密码修改、个人资料更新等完整认证生命周期。 -- 路由保护:仪表盘布局在服务器端通过 getServerSession 获取会话,若无会话则重定向至登录页。 +- 路由保护:仪表盘布局在客户端通过 useSession 获取会话状态,若无会话则重定向至登录页。 - NextAuth 路由:统一暴露 GET/POST,交由 NextAuth 处理认证生命周期。 ```mermaid @@ -260,7 +296,7 @@ LOGIN-->>C : "跳转到 /dashboard 或显示错误" - [app/(auth)/forgot-password/page.tsx](file://frontend/app/(auth)/forgot-password/page.tsx#L1-L101) - [app/(auth)/reset-password/page.tsx](file://frontend/app/(auth)/reset-password/page.tsx#L1-L148) - [app/(auth)/verify-email/page.tsx](file://frontend/app/(auth)/verify-email/page.tsx#L1-L155) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) ### 管理员仪表板系统 - 用户管理:支持用户列表查看、搜索、分页,提供启用/禁用用户和修改套餐功能。 @@ -417,15 +453,15 @@ Tabs --> UIComponents : "标签页导航" **图表来源** - [components/ui/button.tsx:1-57](file://frontend/components/ui/button.tsx#L1-L57) - [components/ui/tabs.tsx:1-56](file://frontend/components/ui/tabs.tsx#L1-L56) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) **章节来源** - [components/ui/button.tsx:1-57](file://frontend/components/ui/button.tsx#L1-L57) - [components/ui/tabs.tsx:1-56](file://frontend/components/ui/tabs.tsx#L1-L56) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) ### 服务器组件与客户端组件的混合使用 -- 服务器组件:仪表盘布局在服务器端通过 getServerSession 校验会话并进行重定向,避免客户端渲染无意义内容。 +- 服务器组件:仪表盘布局在客户端通过 useSession 校验会话并进行重定向,避免客户端渲染无意义内容。 - 客户端组件:登录页、注册页、忘记密码页、重置密码页、邮箱验证页、仪表盘页、管理员仪表板、设置页均标记为客户端组件,以便使用 hooks(如 useSession、useRouter)与交互逻辑。 - Provider 注入:根布局注入 Providers,使子树中的客户端组件可共享会话状态。 - 权限路由:侧边栏根据用户权限动态渲染,管理员用户显示额外的管理后台入口。 @@ -444,13 +480,13 @@ C->>C : "根据权限渲染侧边栏" ``` **图表来源** -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [app/(dashboard)/dashboard/page.tsx](file://frontend/app/(dashboard)/dashboard/page.tsx#L1-L227) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [components/layout/sidebar.tsx:1-63](file://frontend/components/layout/sidebar.tsx#L1-L63) **章节来源** -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [app/(dashboard)/dashboard/page.tsx](file://frontend/app/(dashboard)/dashboard/page.tsx#L1-L227) - [components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [components/layout/sidebar.tsx:1-63](file://frontend/components/layout/sidebar.tsx#L1-L63) @@ -458,7 +494,7 @@ C->>C : "根据权限渲染侧边栏" ### 错误处理机制 - API 层:fetchWithAuth 在非 2xx 时解析错误消息并抛出异常,401 状态自动重定向到登录页,保证上层统一处理。 - 页面层:各认证页面在认证失败时显示错误提示,管理员仪表板和设置页面提供详细的错误反馈和重试机制。 -- 路由保护:服务器端无会话时直接重定向,避免进入受保护页面。 +- 路由保护:客户端无会话时直接重定向,避免进入受保护页面。 - 表单验证:设置页面各表单包含客户端验证,提供即时反馈。 **章节来源** @@ -470,7 +506,148 @@ C->>C : "根据权限渲染侧边栏" - [app/(auth)/verify-email/page.tsx](file://frontend/app/(auth)/verify-email/page.tsx#L1-L155) - [app/(dashboard)/dashboard/admin/page.tsx](file://frontend/app/(dashboard)/dashboard/admin/page.tsx#L1-L435) - [app/(dashboard)/dashboard/settings/page.tsx](file://frontend/app/(dashboard)/dashboard/settings/page.tsx#L1-L445) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) + +## E2E测试框架 + +### Playwright测试配置 +系统集成了完整的E2E测试框架,基于Playwright提供跨浏览器测试能力: + +- **测试环境配置**:支持Chrome、Firefox、Safari三种浏览器并行测试 +- **测试执行策略**:串行执行,失败重试2次,截图仅在失败时捕获 +- **测试报告**:生成HTML格式的详细测试报告 +- **自动化启动**:测试服务器自动启动,支持热重载 + +```mermaid +flowchart TD +Start(["开始E2E测试"]) --> Config["加载Playwright配置"] +Config --> Browser["启动浏览器实例"] +Browser --> Server["启动本地开发服务器"] +Server --> Tests["执行测试用例"] +Tests --> Report["生成测试报告"] +Report --> End(["测试完成"]) +subgraph "测试用例" +Test1["登录页面测试"] +Test2["Dashboard健康状态测试"] +Test3["响应式设计测试"] +Test4["行动建议测试"] +end +subgraph "页面对象" +Page1["LoginPage对象"] +Page2["DashboardPage对象"] +end +``` + +**图表来源** +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) +- [e2e/tests/login.spec.ts:1-126](file://frontend/e2e/tests/login.spec.ts#L1-L126) +- [e2e/tests/dashboard-health.spec.ts:1-264](file://frontend/e2e/tests/dashboard-health.spec.ts#L1-L264) + +### 测试用例覆盖范围 +- **登录页面测试**:验证页面重定向、表单元素、HTML5验证、错误处理、链接功能 +- **Dashboard健康状态测试**:验证页面标题、概览卡片、平台评分、行动建议、骨架屏 +- **响应式设计测试**:验证移动端和桌面端的不同布局表现 +- **颜色传达状态测试**:验证不同健康状态的颜色编码 + +### 页面对象模式 +采用Page Object模式封装测试逻辑: + +- **LoginPage**:封装登录表单的所有交互操作 +- **DashboardPage**:封装Dashboard页面的元素定位和数据提取 + +**章节来源** +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) +- [e2e/tests/login.spec.ts:1-126](file://frontend/e2e/tests/login.spec.ts#L1-L126) +- [e2e/tests/dashboard-health.spec.ts:1-264](file://frontend/e2e/tests/dashboard-health.spec.ts#L1-L264) +- [e2e/pages/login.page.ts:1-36](file://frontend/e2e/pages/login.page.ts#L1-L36) +- [e2e/pages/dashboard.page.ts:1-74](file://frontend/e2e/pages/dashboard.page.ts#L1-L74) + +## 业务组件库 + +### 组件库架构 +GEO业务组件库专注于企业级业务场景,提供高度可定制化的组件解决方案: + +- **组件分类**:按业务领域划分,包括代理管理、监控告警、指标展示等 +- **类型安全**:完整的TypeScript类型定义,确保开发时的类型安全 +- **可复用性**:模块化设计,支持单独导入和批量导出 +- **主题适配**:深度集成Tailwind CSS,支持品牌色彩定制 + +### 核心业务组件 + +#### AgentStatusCard - 代理状态卡片 +提供AI代理的状态可视化展示,支持多种状态指示和详细信息展示: + +- **状态类型**:online(在线)、offline(离线)、busy(繁忙)、error(错误) +- **视觉反馈**:脉冲动画、颜色编码、状态徽章 +- **信息维度**:代理名称、描述、当前任务、活跃时间、完成统计 +- **交互设计**:悬停效果、响应式布局 + +#### AlertCard - 告警卡片 +企业级告警管理系统,支持多级别告警状态和操作: + +- **严重级别**:critical(严重)、warning(警告)、info(信息)、success(成功) +- **视觉层次**:图标、颜色、脉冲动画、状态点 +- **操作功能**:告警关闭、查看详情、批量处理 +- **扩展性**:自定义图标、动作按钮、时间戳 + +#### 其他业务组件 +- **MetricCard**:指标卡片,支持趋势方向和数据点配置 +- **TimelineStep**:时间轴步骤组件,支持多状态展示 +- **PlatformBadge**:平台标识组件,支持配置化平台信息 +- **ClientSwitcher**:客户切换器,支持多租户场景 +- **StageProgress**:阶段进度组件,支持工作流状态展示 + +```mermaid +classDiagram +class BusinessComponents { +<> ++StageProgress ++MetricCard ++AgentStatusCard ++TimelineStep ++PlatformBadge ++ClientSwitcher ++AlertCard +} +class AgentStatusCard { ++name : string ++status : AgentStatus ++currentTask? : string ++lastActiveAt? : string ++completedCount? : number ++render() : JSX.Element +} +class AlertCard { ++alerts : AlertCardItem[] ++title? : string ++onDismiss? : Function ++maxVisible? : number ++render() : JSX.Element +} +class BusinessComponentsIndex { ++exportAll() : void ++importSpecific() : void +} +BusinessComponents --> AgentStatusCard +BusinessComponents --> AlertCard +BusinessComponentsIndex --> BusinessComponents +``` + +**图表来源** +- [components/business/index.ts:1-29](file://frontend/components/business/index.ts#L1-L29) +- [components/business/agent-status-card.tsx:1-134](file://frontend/components/business/agent-status-card.tsx#L1-L134) +- [components/business/alert-card.tsx:1-203](file://frontend/components/business/alert-card.tsx#L1-L203) + +### 组件导出策略 +提供两种导出方式满足不同使用场景: + +- **统一索引导出**:通过index.ts文件提供集中导出,便于批量导入 +- **按需导入**:支持单独导入特定组件,优化打包体积 + +**章节来源** +- [components/business/index.ts:1-29](file://frontend/components/business/index.ts#L1-L29) +- [components/business/agent-status-card.tsx:1-134](file://frontend/components/business/agent-status-card.tsx#L1-L134) +- [components/business/alert-card.tsx:1-203](file://frontend/components/business/alert-card.tsx#L1-L203) ## 依赖分析 - 核心框架:Next.js 14(App Router)、React 18。 @@ -479,6 +656,7 @@ C->>C : "根据权限渲染侧边栏" - 样式:Tailwind CSS、Tailwind 插件(动画)、class-variance-authority、clsx、tailwind-merge。 - 图表:Recharts 用于可视化展示。 - 开发工具:ESLint、TypeScript、PostCSS、Tailwind。 +- **新增**:Playwright(E2E测试框架)、测试工具链。 ```mermaid graph LR @@ -495,16 +673,19 @@ TS["TypeScript"] --> N ESL["ESLint"] --> N PC["PostCSS"] --> TW TABS["Tabs 组件"] --> UI +PW["Playwright"] --> TEST["E2E测试"] +BC["Business Components"] --> UI ``` **图表来源** -- [package.json:1-40](file://frontend/package.json#L1-L40) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [package.json:1-45](file://frontend/package.json#L1-L45) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) - [components/ui/tabs.tsx:1-56](file://frontend/components/ui/tabs.tsx#L1-L56) +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) **章节来源** -- [package.json:1-40](file://frontend/package.json#L1-L40) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [package.json:1-45](file://frontend/package.json#L1-L45) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) - [components/ui/tabs.tsx:1-56](file://frontend/components/ui/tabs.tsx#L1-L56) ## 性能考虑 @@ -514,17 +695,19 @@ TABS["Tabs 组件"] --> UI - 图表渲染:对大数据集使用虚拟化或采样策略(建议项)。 - 资源优化:开启图片与静态资源优化(Next.js 默认支持),按需加载第三方库。 - 构建优化:使用生产构建与代码分割,避免打包体积过大。 -- 权限控制:服务器端权限检查,减少客户端无意义的渲染。 +- 权限控制:客户端权限检查,减少无意义的渲染。 +- **新增**:E2E测试性能:并行测试执行,智能重试机制,减少测试时间。 ## 故障排除指南 - 登录失败:检查凭据是否正确,确认后端认证接口可用;查看登录页错误提示与 NextAuth 回调日志。 - 会话丢失:确认 Cookie 设置、SameSite 与跨域配置;检查 NextAuth 回调是否正确写入 token。 -- 仪表盘空白:确认服务器端 getServerSession 返回有效会话;检查客户端 useSession 是否拿到访问令牌。 +- 仪表盘空白:确认客户端 useSession 返回有效会话;检查客户端状态管理。 - 认证页面异常:检查对应认证页面的错误状态和网络请求;确认 API 端点是否正确。 - 管理员功能不可用:确认用户 is_admin 标识;检查侧边栏权限渲染逻辑。 - 设置页面问题:检查各标签页的状态管理;确认 API 调用和表单验证逻辑。 - API 请求失败:查看 fetchWithAuth 抛出的错误信息,确认后端接口路径与鉴权头是否正确。 - 样式异常:检查 Tailwind 配置 content 路径与 CSS 变量是否生效;确认暗色模式 class 是否正确切换。 +- **新增**:E2E测试失败:检查测试环境配置、页面元素定位、网络请求超时;查看测试报告详细信息。 **章节来源** - [app/(auth)/login/page.tsx](file://frontend/app/(auth)/login/page.tsx#L1-L93) @@ -534,21 +717,27 @@ TABS["Tabs 组件"] --> UI - [app/(auth)/verify-email/page.tsx](file://frontend/app/(auth)/verify-email/page.tsx#L1-L155) - [app/(dashboard)/dashboard/admin/page.tsx](file://frontend/app/(dashboard)/dashboard/admin/page.tsx#L1-L435) - [app/(dashboard)/dashboard/settings/page.tsx](file://frontend/app/(dashboard)/dashboard/settings/page.tsx#L1-L445) -- [app/(dashboard)/layout.tsx](file://frontend/app/(dashboard)/layout.tsx#L1-L27) +- [app/(dashboard)/layout.tsx:1-146](file://frontend/app/(dashboard)/layout.tsx#L1-L146) - [lib/api.ts:1-154](file://frontend/lib/api.ts#L1-L154) -- [tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) +- [tailwind.config.ts:1-121](file://frontend/tailwind.config.ts#L1-L121) +- [playwright.config.ts:1-39](file://frontend/playwright.config.ts#L1-L39) ## 结论 -本架构以 Next.js 14 App Router 为核心,结合服务器组件与客户端组件的混合模式,实现了清晰的页面组织与路由保护;通过 NextAuth.js 的凭据提供者与 JWT 会话策略,完成了前后端认证协作,支持完整的认证生命周期;UI 组件库以 Radix UI 与 Tailwind 为基础,具备良好的可维护性与一致性,新增的 Tabs 组件支持复杂的多标签页界面;API 客户端统一处理鉴权与错误,配合页面层的状态与错误处理,形成完整的前端数据流。系统现已扩展为完整的认证体系和管理功能,支持管理员权限和用户自助管理。建议在后续迭代中进一步完善缓存与重试、图表渲染优化与构建体积治理,持续提升用户体验与可维护性。 +本架构以 Next.js 14 App Router 为核心,结合服务器组件与客户端组件的混合模式,实现了清晰的页面组织与路由保护;通过 NextAuth.js 的凭据提供者与 JWT 会话策略,完成了前后端认证协作,支持完整的认证生命周期;UI 组件库以 Radix UI 与 Tailwind 为基础,具备良好的可维护性与一致性,新增的 Tabs 组件支持复杂的多标签页界面;API 客户端统一处理鉴权与错误,配合页面层的状态与错误处理,形成完整的前端数据流。 + +**更新** 新增的E2E测试框架显著提升了代码质量保证能力,通过Playwright实现跨浏览器兼容性测试;业务组件库扩展了企业级应用场景的组件支持,包括代理状态管理、告警系统、指标展示等功能;仪表板布局重构提供了更好的用户体验和导航效率。建议在后续迭代中进一步完善测试覆盖率、组件文档化和性能监控,持续提升系统的稳定性和可维护性。 ## 附录 - 最佳实践清单 - 使用路由组隔离功能域,保持页面组织清晰。 - - 将路由保护放在服务器端,优先保障安全性。 + - 将路由保护放在客户端,优先保障用户体验。 - 仅在需要时标记客户端组件,减少水合成本。 - 统一错误处理与用户反馈,提供明确的重试与刷新能力。 - 严格类型约束,结合 TypeScript 与自定义类型扩展,降低运行时风险。 - 支持管理员权限的渐进式增强,避免过度设计。 - 使用标签页组件组织复杂设置界面,提升用户体验。 - 实施细粒度的权限控制,确保数据安全。 - - 持续优化构建产物与运行时性能,关注首屏与交互延迟。 \ No newline at end of file + - 持续优化构建产物与运行时性能,关注首屏与交互延迟。 + - **新增**:建立完善的E2E测试流程,确保跨浏览器兼容性。 + - **新增**:文档化业务组件使用规范,提升团队协作效率。 + - **新增**:实施测试驱动开发,提高代码质量和稳定性。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端系统架构/后端系统架构.md b/.qoder/repowiki/zh/content/后端系统架构/后端系统架构.md index 168e46d..21f4d87 100644 --- a/.qoder/repowiki/zh/content/后端系统架构/后端系统架构.md +++ b/.qoder/repowiki/zh/content/后端系统架构/后端系统架构.md @@ -26,17 +26,30 @@ - [backend/app/services/subscription.py](file://backend/app/services/subscription.py) - [backend/app/workers/scheduler.py](file://backend/app/workers/scheduler.py) - [backend/app/workers/citation_engine.py](file://backend/app/workers/citation_engine.py) +- [backend/app/workers/llm_adapter.py](file://backend/app/workers/llm_adapter.py) +- [backend/app/agent_framework/base.py](file://backend/app/agent_framework/base.py) +- [backend/app/agent_framework/dispatcher.py](file://backend/app/agent_framework/dispatcher.py) +- [backend/app/agent_framework/registry.py](file://backend/app/agent_framework/registry.py) +- [backend/app/agent_framework/pipeline/engine.py](file://backend/app/agent_framework/pipeline/engine.py) +- [backend/app/agent_framework/pipeline/loader.py](file://backend/app/agent_framework/pipeline/loader.py) +- [backend/app/agent_framework/pipeline/schema.py](file://backend/app/agent_framework/pipeline/schema.py) +- [backend/app/agent_framework/protocol.py](file://backend/app/agent_framework/protocol.py) +- [backend/app/agent_framework/agents/content_generator_agent.py](file://backend/app/agent_framework/agents/content_generator_agent.py) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py](file://backend/app/agent_framework/agents/geo_optimizer_agent.py) +- [backend/app/services/llm/factory.py](file://backend/app/services/llm/factory.py) +- [backend/app/models/agent.py](file://backend/app/models/agent.py) +- [backend/pipelines/content_production.yaml](file://backend/pipelines/content_production.yaml) +- [backend/pipelines/diagnosis.yaml](file://backend/pipelines/diagnosis.yaml) ## 更新摘要 **所做更改** -- 新增中间件系统章节,包含限流中间件和日志中间件 -- 新增管理员服务和API路由,支持系统管理和用户管理 -- 新增订阅服务和API路由,支持套餐管理和订阅管理 -- 新增PDF报告服务,支持CSV和PDF格式导出 -- 更新项目结构图,反映新增模块和文件 -- 更新数据模型关系图,包含订阅和查询任务模型 -- 更新架构总览图,展示新增中间件和服务层 +- 新增代理框架架构章节,包含Agent基类、注册中心、任务分发器和工作流引擎 +- 新增LLM服务集成章节,包含LLM工厂模式和多提供商支持 +- 新增工作器系统扩展章节,包含LLM适配器和平台适配器 +- 新增分布式发布系统章节,包含Pipeline编排和任务编排 +- 更新项目结构图,反映新增的代理框架和LLM服务模块 +- 更新架构总览图,展示新增的代理系统和LLM集成 ## 目录 1. [引言](#引言) @@ -44,20 +57,24 @@ 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) -6. [中间件系统](#中间件系统) -7. [管理员服务](#管理员服务) -8. [订阅服务](#订阅服务) -9. [报告服务](#报告服务) -10. [依赖关系分析](#依赖关系分析) -11. [性能考量](#性能考量) -12. [故障排查指南](#故障排查指南) -13. [结论](#结论) -14. [附录](#附录) +6. [代理框架架构](#代理框架架构) +7. [LLM服务集成](#llm服务集成) +8. [工作器系统扩展](#工作器系统扩展) +9. [分布式发布系统](#分布式发布系统) +10. [中间件系统](#中间件系统) +11. [管理员服务](#管理员服务) +12. [订阅服务](#订阅服务) +13. [报告服务](#报告服务) +14. [依赖关系分析](#依赖关系分析) +15. [性能考量](#性能考量) +16. [故障排查指南](#故障排查指南) +17. [结论](#结论) +18. [附录](#附录) ## 引言 本文件为 GEO 平台后端系统的架构文档,基于 FastAPI 构建,采用异步 SQLAlchemy ORM、APScheduler 定时任务与多平台适配器模式,实现查询词管理、引用检测与报告统计等功能。文档覆盖应用配置、中间件、路由组织、生命周期管理、数据库连接与 ORM、异步处理、认证与权限控制、API 设计与错误处理、系统监控与日志、性能优化策略,并给出架构决策的技术背景与权衡。 -**更新** 本次更新反映了应用的重大功能扩展,包括中间件系统的引入、管理员管理功能、订阅管理系统和报告导出功能。 +**更新** 本次更新显著扩展了系统架构,新增代理框架架构、LLM服务集成、工作器系统扩展和分布式发布系统等核心组件,形成了更加完整的企业级AI内容生产与管理平台。 ## 项目结构 后端采用分层与功能域结合的组织方式: @@ -68,7 +85,10 @@ - 中间件层:app/middleware/(logging_middleware、rate_limit) - 模型层:app/models/(SQLAlchemy ORM 映射) - 服务层:app/services/(business logic encapsulation) -- 工作器与调度:app/workers/(APScheduler 调度器、引用检测引擎、平台适配器) +- 代理框架:app/agent_framework/(Agent基类、注册中心、任务分发器、工作流引擎) +- LLM服务:app/services/llm/(LLM工厂、提供商适配器) +- 工作器与调度:app/workers/(APScheduler 调度器、引用检测引擎、平台适配器、LLM适配器) +- 流水线定义:pipelines/(YAML配置文件) - 测试:tests/(pytest) ```mermaid @@ -93,20 +113,41 @@ REPORTS["api/reports.py"] SUBSCRIPTIONS["api/subscriptions.py"] DEPS["api/deps.py"] end +subgraph "代理框架" +AGENT_BASE["agent_framework/base.py"] +REGISTRY["agent_framework/registry.py"] +DISPATCHER["agent_framework/dispatcher.py"] +PIPELINE_ENGINE["agent_framework/pipeline/engine.py"] +PIPELINE_LOADER["agent_framework/pipeline/loader.py"] +PIPELINE_SCHEMA["agent_framework/pipeline/schema.py"] +PROTOCOL["agent_framework/protocol.py"] +END +subgraph "LLM服务" +LLM_FACTORY["services/llm/factory.py"] +OPENAI_PROVIDER["services/llm/openai_provider.py"] +DEEPSEEK_PROVIDER["services/llm/deepseek_provider.py"] +END subgraph "模型与服务" MODEL_USER["models/user.py"] MODEL_QUERY["models/query.py"] MODEL_CIT["models/citation_record.py"] MODEL_SUB["models/subscription.py"] MODEL_TASK["models/query_task.py"] +MODEL_AGENT["models/agent.py"] SVC_AUTH["services/auth.py"] SVC_ADMIN["services/admin.py"] SVC_SUB["services/subscription.py"] -end +END subgraph "工作器与调度" SCHED["workers/scheduler.py"] ENGINE["workers/citation_engine.py"] -end +LLM_ADAPTER["workers/llm_adapter.py"] +PLATFORMS["workers/platforms/"] +END +subgraph "流水线定义" +CONTENT_PRODUCTION["pipelines/content_production.yaml"] +DIAGNOSIS["pipelines/diagnosis.yaml"] +END MAIN --> LOGMW MAIN --> RATEMW MAIN --> AUTH @@ -132,7 +173,14 @@ SCHED --> DB SCHED --> ENGINE ENGINE --> MODEL_QUERY ENGINE --> MODEL_CIT -DB --> CFG +LLM_ADAPTER --> CFG +REGISTRY --> DB +DISPATCHER --> DB +DISPATCHER --> AGENT_BASE +PIPELINE_ENGINE --> DISPATCHER +PIPELINE_LOADER --> PIPELINE_SCHEMA +LLM_FACTORY --> OPENAI_PROVIDER +LLM_FACTORY --> DEEPSEEK_PROVIDER ``` **图表来源** @@ -141,11 +189,14 @@ DB --> CFG - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/middleware/logging_middleware.py:1-24](file://backend/app/middleware/logging_middleware.py#L1-L24) - [backend/app/middleware/rate_limit.py:1-83](file://backend/app/middleware/rate_limit.py#L1-L83) -- [backend/app/api/admin.py:1-108](file://backend/app/api/admin.py#L1-L108) -- [backend/app/api/reports.py:1-75](file://backend/app/api/reports.py#L1-L75) -- [backend/app/api/subscriptions.py:1-77](file://backend/app/api/subscriptions.py#L1-L77) -- [backend/app/services/admin.py:1-188](file://backend/app/services/admin.py#L1-L188) -- [backend/app/services/subscription.py:1-155](file://backend/app/services/subscription.py#L1-L155) +- [backend/app/agent_framework/base.py:1-223](file://backend/app/agent_framework/base.py#L1-L223) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) +- [backend/app/workers/llm_adapter.py:1-281](file://backend/app/workers/llm_adapter.py#L1-L281) +- [backend/pipelines/content_production.yaml:1-65](file://backend/pipelines/content_production.yaml#L1-L65) +- [backend/pipelines/diagnosis.yaml:1-30](file://backend/pipelines/diagnosis.yaml#L1-L30) **章节来源** - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) @@ -159,8 +210,11 @@ DB --> CFG - 数据库:异步 SQLAlchemy 引擎与会话工厂,依赖注入式获取会话。 - 认证与权限:OAuth2 密码流 + JWT,依赖注入解析当前用户,未授权时抛出 401。 - 引擎与调度:APScheduler 定时扫描到期查询,调用 CitationEngine 执行并持久化结果。 +- **新增** 代理框架:基于Redis的消息队列,支持Agent注册、发现、任务分发和工作流编排。 +- **新增** LLM服务:统一的LLM提供商工厂,支持OpenAI和DeepSeek等多种提供商。 +- **新增** 分布式发布:基于YAML的流水线编排系统,支持复杂的内容生产工作流。 -**更新** 新增中间件系统提供限流和日志功能,增强系统的安全性和可观测性。 +**更新** 新增代理框架、LLM服务集成和分布式发布系统,显著增强了系统的智能化和自动化能力。 **章节来源** - [backend/app/main.py:13-48](file://backend/app/main.py#L13-L48) @@ -168,7 +222,7 @@ DB --> CFG - [backend/app/api/deps.py:13-43](file://backend/app/api/deps.py#L13-L43) ## 架构总览 -系统采用"API 层-中间件层-服务层-模型层-基础设施"的分层架构,配合异步 I/O 与定时任务,实现高并发与可扩展的查询与检测能力。 +系统采用"API 层-中间件层-服务层-模型层-基础设施"的分层架构,配合异步 I/O 与定时任务,实现高并发与可扩展的查询与检测能力。新增的代理框架通过Redis实现分布式任务调度,LLM服务提供统一的AI能力接口,分布式发布系统支持复杂的工作流编排。 ```mermaid graph TB @@ -188,6 +242,12 @@ SVC_SUB["订阅服务
套餐管理/订阅流程"] DB["异步数据库
Session 工厂"] SCHED["查询调度器
APScheduler"] ENGINE["引用检测引擎
平台适配器"] +LLM_ADAPTER["LLM适配器
DeepSeek API"] +AGENT_FRAMEWORK["代理框架
Redis队列/Agent管理"] +REGISTRY["注册中心
Agent注册/发现"] +DISPATCHER["任务分发器
消息队列/状态管理"] +PIPELINE_ENGINE["工作流引擎
YAML编排/DAG执行"] +LLM_SERVICE["LLM服务
工厂模式/多提供商"] CLIENT --> FASTAPI FASTAPI --> MIDDLEWARE MIDDLEWARE --> ROUTER_AUTH @@ -215,6 +275,14 @@ SVC_SUB --> DB SCHED --> DB SCHED --> ENGINE ENGINE --> DB +LLM_ADAPTER --> DB +AGENT_FRAMEWORK --> REGISTRY +AGENT_FRAMEWORK --> DISPATCHER +AGENT_FRAMEWORK --> PIPELINE_ENGINE +DISPATCHER --> DB +REGISTRY --> DB +PIPELINE_ENGINE --> DB +LLM_SERVICE --> DB ``` **图表来源** @@ -227,6 +295,12 @@ ENGINE --> DB - [backend/app/services/subscription.py:69-155](file://backend/app/services/subscription.py#L69-L155) - [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95) - [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309) +- [backend/app/workers/llm_adapter.py:1-281](file://backend/app/workers/llm_adapter.py#L1-L281) +- [backend/app/agent_framework/base.py:1-223](file://backend/app/agent_framework/base.py#L1-L223) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) ## 详细组件分析 @@ -380,6 +454,9 @@ Wait --> Tick - 引用记录:外键查询、平台、是否引用、位置、文本、竞争品牌、原始响应、时间戳。 - 订阅:外键用户、套餐类型、状态、开始结束日期、金额、支付方式、时间戳。 - 查询任务:外键查询、平台、状态、错误信息、调度时间、开始完成时间。 +- **新增** Agent注册表:Agent元数据、状态、能力声明、心跳时间。 +- **新增** Agent任务表:任务执行状态、输入输出数据、执行指标。 +- **新增** Agent任务日志表:任务执行日志、进度跟踪、错误信息。 ```mermaid erDiagram @@ -440,11 +517,55 @@ text error_message timestamp scheduled_at timestamp started_at timestamp completed_at +timestamp created_at +timestamp updated_at +} +AGENT_REGISTRY { +uuid id PK +string name UK +string display_name +string agent_type +string description +string version +string endpoint +string status +jsonb capabilities +timestamp last_heartbeat +timestamp created_at +timestamp updated_at +} +AGENT_TASKS { +uuid id PK +uuid agent_id FK +string task_type +string status +int priority +jsonb input_data +jsonb output_data +text error_message +uuid created_by +uuid organization_id FK +uuid project_id FK +timestamp scheduled_at +timestamp started_at +timestamp completed_at +timestamp created_at +} +AGENT_TASK_LOGS { +uuid id PK +uuid task_id FK +uuid agent_id FK +string log_level +text message +jsonb extra_metadata +timestamp created_at } USERS ||--o{ QUERIES : "拥有" QUERIES ||--o{ CITATION_RECORDS : "产生" USERS ||--o{ SUBSCRIPTIONS : "订阅" QUERIES ||--o{ QUERY_TASKS : "包含" +AGENT_REGISTRY ||--o{ AGENT_TASKS : "执行" +AGENT_TASKS ||--o{ AGENT_TASK_LOGS : "记录" ``` **图表来源** @@ -453,6 +574,7 @@ QUERIES ||--o{ QUERY_TASKS : "包含" - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) +- [backend/app/models/agent.py:12-206](file://backend/app/models/agent.py#L12-L206) **章节来源** - [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41) @@ -460,6 +582,292 @@ QUERIES ||--o{ QUERY_TASKS : "包含" - [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42) - [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37) - [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39) +- [backend/app/models/agent.py:1-206](file://backend/app/models/agent.py#L1-L206) + +## 代理框架架构 + +### Agent基类与生命周期管理 +代理框架的核心是BaseAgent基类,它定义了所有Agent的标准生命周期和行为: +- **启动流程**:初始化Redis连接、注册到注册中心、启动心跳、开始监听任务队列 +- **任务执行**:异步监听Redis队列,执行具体任务逻辑,上报进度和结果 +- **状态管理**:维护Agent在线状态、忙碌状态,支持优雅停机 +- **心跳机制**:定期向注册中心上报心跳,保持活跃状态 + +```mermaid +sequenceDiagram +participant Agent as "Agent实例" +participant Redis as "Redis服务器" +participant Registry as "注册中心" +participant Dispatcher as "任务分发器" +Agent->>Agent : start() +Agent->>Redis : 连接Redis +Agent->>Registry : register(capabilities) +Registry-->>Agent : 注册成功 +Agent->>Agent : 启动心跳循环 +Agent->>Agent : 启动任务监听 +loop 每30秒 +Agent->>Registry : update_heartbeat() +end +Redis-->>Agent : 任务消息 +Agent->>Agent : execute(task) +Agent->>Dispatcher : handle_result(result) +Agent->>Agent : report_progress(progress) +``` + +**图表来源** +- [backend/app/agent_framework/base.py:52-114](file://backend/app/agent_framework/base.py#L52-L114) +- [backend/app/agent_framework/base.py:148-182](file://backend/app/agent_framework/base.py#L148-L182) + +### 注册中心与Agent发现 +注册中心负责管理所有Agent的生命周期和状态: +- **注册流程**:Agent启动时向注册中心注册,保存能力声明和端点信息 +- **状态维护**:实时更新Agent心跳时间,超时自动标记为离线 +- **发现机制**:根据任务类型动态查找可用的Agent实例 +- **健康检查**:定期扫描超时的Agent并更新状态 + +```mermaid +flowchart TD +Start["Agent启动"] --> Connect["连接Redis"] +Connect --> Register["向注册中心注册"] +Register --> SaveInfo["保存Agent信息
能力声明/端点/状态"] +SaveInfo --> Heartbeat["启动心跳循环"] +Heartbeat --> Monitor["监控Agent状态"] +Monitor --> Timeout{"心跳超时?"} +Timeout -- 是 --> MarkOffline["标记为离线"] +Timeout -- 否 --> Monitor +Monitor --> Discover["Agent发现"] +Discover --> Match{"任务类型匹配?"} +Match -- 是 --> Dispatch["分发任务"] +Match -- 否 --> Wait["等待其他Agent"] +``` + +**图表来源** +- [backend/app/agent_framework/registry.py:29-80](file://backend/app/agent_framework/registry.py#L29-L80) +- [backend/app/agent_framework/registry.py:156-172](file://backend/app/agent_framework/registry.py#L156-L172) +- [backend/app/agent_framework/registry.py:174-201](file://backend/app/agent_framework/registry.py#L174-L201) + +### 任务分发器与消息队列 +任务分发器通过Redis实现Agent间的异步通信: +- **任务分发**:将TaskMessage推送到指定Agent的队列 +- **状态管理**:维护AgentTask表,跟踪任务执行状态 +- **结果处理**:接收Agent返回的TaskResult,更新数据库状态 +- **进度上报**:处理TaskProgress消息,记录执行进度 + +```mermaid +sequenceDiagram +participant API as "API服务" +participant Dispatcher as "任务分发器" +participant Redis as "Redis队列" +participant Agent as "目标Agent" +participant DB as "数据库" +API->>Dispatcher : dispatch(task) +Dispatcher->>DB : 写入AgentTask记录 +DB-->>Dispatcher : 确认写入 +Dispatcher->>Redis : LPUSH agent : {name} : tasks +Redis-->>Agent : 任务消息 +Agent->>Agent : execute(task) +Agent->>Dispatcher : handle_result(result) +Dispatcher->>DB : 更新任务状态 +DB-->>API : 任务完成 +``` + +**图表来源** +- [backend/app/agent_framework/dispatcher.py:54-117](file://backend/app/agent_framework/dispatcher.py#L54-L117) +- [backend/app/agent_framework/dispatcher.py:169-218](file://backend/app/agent_framework/dispatcher.py#L169-L218) + +**章节来源** +- [backend/app/agent_framework/base.py:1-223](file://backend/app/agent_framework/base.py#L1-L223) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) + +## LLM服务集成 + +### LLM工厂模式与多提供商支持 +LLM服务采用工厂模式统一管理不同的AI提供商: +- **OpenAI提供商**:支持GPT系列模型,提供标准的ChatCompletion接口 +- **DeepSeek提供商**:支持DeepSeek系列模型,提供高性能的推理能力 +- **统一接口**:所有提供商实现相同的LLMProvider接口,支持透明切换 +- **配置管理**:通过环境变量和配置文件管理API密钥和模型参数 + +```mermaid +flowchart TD +Factory["LLM工厂"] --> OpenAI["OpenAI提供商"] +Factory --> DeepSeek["DeepSeek提供商"] +OpenAI --> GPT4["GPT-4模型"] +OpenAI --> GPT35["GPT-3.5模型"] +DeepSeek --> DeepSeekChat["DeepSeek-chat模型"] +DeepSeek --> DeepSeekCoder["DeepSeek-coder模型"] +Factory --> Config["配置管理"] +Config --> Env["环境变量"] +Config --> Settings["应用配置"] +Env --> Factory +Settings --> Factory +``` + +**图表来源** +- [backend/app/services/llm/factory.py:8-66](file://backend/app/services/llm/factory.py#L8-L66) +- [backend/app/services/llm/factory.py:25-50](file://backend/app/services/llm/factory.py#L25-L50) + +### LLM适配器与品牌引用检测 +LLM适配器专门用于品牌引用检测任务,集成DeepSeek API: +- **提示词工程**:精心设计的提示词模板,确保准确的品牌识别 +- **JSON输出解析**:标准化的JSON格式输出,包含引用状态、置信度等信息 +- **错误处理**:完善的异常处理和重试机制,确保服务稳定性 +- **模拟模式**:在禁用LLM时提供模拟结果,保证系统可用性 + +```mermaid +sequenceDiagram +participant Engine as "引用检测引擎" +participant Adapter as "LLM适配器" +participant DeepSeek as "DeepSeek API" +Engine->>Adapter : query_brand_citation(keyword, brand, aliases) +Adapter->>Adapter : 构建提示词 +Adapter->>DeepSeek : chat.completions.create +DeepSeek-->>Adapter : JSON响应 +Adapter->>Adapter : 解析JSON输出 +Adapter-->>Engine : CitationResult +``` + +**图表来源** +- [backend/app/workers/llm_adapter.py:71-110](file://backend/app/workers/llm_adapter.py#L71-L110) +- [backend/app/workers/llm_adapter.py:220-270](file://backend/app/workers/llm_adapter.py#L220-L270) + +**章节来源** +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) +- [backend/app/workers/llm_adapter.py:1-281](file://backend/app/workers/llm_adapter.py#L1-L281) + +## 工作器系统扩展 + +### 平台适配器与多平台支持 +工作器系统扩展了原有的平台适配器,支持更多AI平台: +- **现有平台**:Doubao、Kimi、Qingyan、Tiangong、Tongyi、Wenxin、Xinghuo +- **搜索引擎**:通用搜索平台适配器 +- **统一接口**:所有平台实现相同的BasePlatform接口 +- **配置管理**:通过配置文件管理平台API密钥和参数 + +```mermaid +graph TB +PlatformBase["平台基类
BasePlatform"] +Doubao["Doubao平台
doubao.py"] +Kimi["Kimi平台
kimi.py"] +Qingyan["Qingyan平台
qingyan.py"] +SearchEngine["搜索引擎
search_engine.py"] +Tiangong["Tiangong平台
tiangong.py"] +Tongyi["Tongyi平台
tongyi.py"] +Wenxin["Wenxin平台
wenxin.py"] +Xinghuo["Xinghuo平台
xinghuo.py"] +PlatformBase --> Doubao +PlatformBase --> Kimi +PlatformBase --> Qingyan +PlatformBase --> SearchEngine +PlatformBase --> Tiangong +PlatformBase --> Tongyi +PlatformBase --> Wenxin +PlatformBase --> Xinghuo +``` + +**图表来源** +- [backend/app/workers/platforms/base.py](file://backend/app/workers/platforms/base.py) +- [backend/app/workers/platforms/doubao.py](file://backend/app/workers/platforms/doubao.py) +- [backend/app/workers/platforms/kimi.py](file://backend/app/workers/platforms/kimi.py) +- [backend/app/workers/platforms/qingyan.py](file://backend/app/workers/platforms/qingyan.py) +- [backend/app/workers/platforms/search_engine.py](file://backend/app/workers/platforms/search_engine.py) +- [backend/app/workers/platforms/tiangong.py](file://backend/app/workers/platforms/tiangong.py) +- [backend/app/workers/platforms/tongyi.py](file://backend/app/workers/platforms/tongyi.py) +- [backend/app/workers/platforms/wenxin.py](file://backend/app/workers/platforms/wenxin.py) +- [backend/app/workers/platforms/xinghuo.py](file://backend/app/workers/platforms/xinghuo.py) + +### 内容生成Agent与GEO优化Agent +新增的专业Agent实现了特定的AI内容生成功能: +- **内容生成Agent**:支持选题生成和文章生成,集成RAG知识库检索 +- **GEO优化Agent**:专门优化内容在AI搜索引擎中的可见性 +- **进度上报**:实时上报任务执行进度,支持用户监控 +- **错误处理**:完善的异常处理和重试机制 + +```mermaid +flowchart TD +ContentAgent["内容生成Agent"] --> Topics["选题生成"] +ContentAgent --> Article["文章生成"] +Topics --> RAG["RAG知识库检索"] +Article --> LLM["LLM调用"] +GEOAgent["GEO优化Agent"] --> Optimize["内容优化"] +Optimize --> LLM2["LLM调用"] +RAG --> LLM +``` + +**图表来源** +- [backend/app/agent_framework/agents/content_generator_agent.py:111-182](file://backend/app/agent_framework/agents/content_generator_agent.py#L111-L182) +- [backend/app/agent_framework/agents/content_generator_agent.py:184-252](file://backend/app/agent_framework/agents/content_generator_agent.py#L184-L252) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:104-180](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L104-L180) + +**章节来源** +- [backend/app/agent_framework/agents/content_generator_agent.py:1-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L1-L299) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:1-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L1-L198) + +## 分布式发布系统 + +### Pipeline工作流编排 +分布式发布系统基于YAML配置实现复杂的工作流编排: +- **内容生产流水线**:从选题到发布的完整内容生产流程 +- **诊断分析流水线**:引用检测与竞争分析的诊断流程 +- **DAG执行**:支持有向无环图的任务依赖关系 +- **变量解析**:支持复杂的变量引用和上下文传递 + +```mermaid +graph TB +ContentProduction["内容生产流水线"] --> TopicSelection["选题选择"] +ContentProduction --> ContentGeneration["内容生成"] +ContentProduction --> DeAIProcessing["去AI化处理"] +ContentProduction --> GEOOptimization["GEO优化"] +ContentProduction --> RuleValidation["规则验证"] +TopicSelection --> ContentGeneration +ContentGeneration --> DeAIProcessing +DeAIProcessing --> GEOOptimization +GEOOptimization --> RuleValidation +Diagnosis["诊断分析流水线"] --> CitationDetection["引用检测"] +Diagnosis --> CompetitorAnalysis["竞争分析"] +CitationDetection --> CompetitorAnalysis +``` + +**图表来源** +- [backend/pipelines/content_production.yaml:9-65](file://backend/pipelines/content_production.yaml#L9-L65) +- [backend/pipelines/diagnosis.yaml:8-30](file://backend/pipelines/diagnosis.yaml#L8-L30) + +### 工作流引擎与任务编排 +工作流引擎负责执行复杂的任务编排逻辑: +- **拓扑排序**:使用Kahn算法进行DAG拓扑排序 +- **条件执行**:支持基于条件表达式的任务执行 +- **重试机制**:支持任务级别的重试和超时控制 +- **进度跟踪**:实时跟踪每个阶段的执行进度 + +```mermaid +sequenceDiagram +participant User as "用户" +participant Engine as "工作流引擎" +participant Dispatcher as "任务分发器" +participant Agent as "Agent实例" +User->>Engine : execute(pipeline, context) +Engine->>Engine : 拓扑排序 +Engine->>Engine : 变量解析 +Engine->>Dispatcher : 分发阶段任务 +Dispatcher->>Agent : 任务消息 +Agent->>Agent : 执行任务 +Agent->>Dispatcher : 任务结果 +Dispatcher->>Engine : 更新状态 +Engine->>Engine : 下一阶段执行 +Engine-->>User : 完整执行结果 +``` + +**图表来源** +- [backend/app/agent_framework/pipeline/engine.py:51-176](file://backend/app/agent_framework/pipeline/engine.py#L51-L176) +- [backend/app/agent_framework/pipeline/engine.py:256-327](file://backend/app/agent_framework/pipeline/engine.py#L256-L327) + +**章节来源** +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/pipeline/loader.py:1-283](file://backend/app/agent_framework/pipeline/loader.py#L1-L283) +- [backend/app/agent_framework/pipeline/schema.py:1-102](file://backend/app/agent_framework/pipeline/schema.py#L1-L102) +- [backend/pipelines/content_production.yaml:1-65](file://backend/pipelines/content_production.yaml#L1-L65) +- [backend/pipelines/diagnosis.yaml:1-30](file://backend/pipelines/diagnosis.yaml#L1-L30) ## 中间件系统 @@ -619,6 +1027,9 @@ Reports-->>Client : Response PDF ## 依赖关系分析 - 组件内聚:API 路由与服务层职责清晰,模型仅负责映射。 - 组件耦合:API 依赖服务,服务依赖数据库与配置;调度器依赖引擎与数据库;引擎依赖平台适配器。 +- **新增** 代理框架:Agent依赖Redis和注册中心,任务分发器依赖数据库和Redis。 +- **新增** LLM服务:Agent依赖LLM工厂,LLM工厂依赖具体的提供商实现。 +- **新增** 工作流引擎:依赖任务分发器和管道加载器,支持复杂的任务编排。 - 依赖注入:通过 FastAPI 依赖系统注入数据库会话与当前用户。 - 循环依赖:未见明显循环依赖。 @@ -642,6 +1053,13 @@ DEPS --> DB SCHED["workers/scheduler.py"] --> DB SCHED --> ENGINE["workers/citation_engine.py"] ENGINE --> MODELS["models/*.py"] +LLM_ADAPTER["workers/llm_adapter.py"] --> LLM_FACTORY["services/llm/factory.py"] +LLM_FACTORY --> PROVIDERS["services/llm/*"] +AGENT_FRAMEWORK["agent_framework/*"] --> REGISTRY["agent_framework/registry.py"] +AGENT_FRAMEWORK --> DISPATCHER["agent_framework/dispatcher.py"] +DISPATCHER --> MODELS["models/agent.py"] +PIPELINE_ENGINE["agent_framework/pipeline/engine.py"] --> DISPATCHER +PIPELINE_LOADER["agent_framework/pipeline/loader.py"] --> PIPELINE_SCHEMA["agent_framework/pipeline/schema.py"] ``` **图表来源** @@ -652,6 +1070,13 @@ ENGINE --> MODELS["models/*.py"] - [backend/app/api/subscriptions.py:1-77](file://backend/app/api/subscriptions.py#L1-L77) - [backend/app/services/admin.py:1-188](file://backend/app/services/admin.py#L1-L188) - [backend/app/services/subscription.py:1-155](file://backend/app/services/subscription.py#L1-L155) +- [backend/app/workers/llm_adapter.py:1-281](file://backend/app/workers/llm_adapter.py#L1-L281) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/pipeline/loader.py:1-283](file://backend/app/agent_framework/pipeline/loader.py#L1-L283) +- [backend/app/agent_framework/pipeline/schema.py:1-102](file://backend/app/agent_framework/pipeline/schema.py#L1-L102) **章节来源** - [backend/app/api/auth.py:1-43](file://backend/app/api/auth.py#L1-L43) @@ -665,17 +1090,21 @@ ENGINE --> MODELS["models/*.py"] - [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41) - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) - [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42) +- [backend/app/models/agent.py:1-206](file://backend/app/models/agent.py#L1-L206) ## 性能考量 - 异步 I/O:数据库与平台查询均采用异步,提升并发吞吐。 - 会话管理:显式事务边界,避免长事务占用连接池。 - 定时任务:APScheduler 异步调度,事件循环兼容处理,降低阻塞风险。 - 索引优化:查询与引用表建立复合索引,加速过滤与排序。 +- **新增** Redis缓存:代理框架使用Redis作为消息队列,支持高并发任务分发。 +- **新增** LLM优化:LLM调用采用异步模式,支持批量处理和错误重试。 +- **新增** 工作流优化:DAG拓扑排序确保任务执行顺序,避免死锁和循环依赖。 - 缓存建议:可引入 Redis 缓存热点查询结果与用户会话信息(当前配置已准备)。 - 日志采样:生产环境建议开启采样与结构化日志,避免高频日志影响性能。 - **中间件性能**:限流中间件使用内存存储,性能开销低;日志中间件仅记录必要信息。 -**更新** 新增中间件系统的性能考量,包括内存存储的限流机制和结构化日志的性能影响。 +**更新** 新增代理框架、LLM服务和工作流系统的性能考量,包括Redis缓存、异步LLM调用和DAG执行优化。 ## 故障排查指南 - 认证失败:检查 JWT 秘钥、过期时间与前端令牌传递;确认 OAuth2 tokenUrl 与 Bearer 头正确。 @@ -683,11 +1112,14 @@ ENGINE --> MODELS["models/*.py"] - 定时任务异常:关注调度器日志,检查查询状态与平台适配器可用性;确认 next_query_at 计算逻辑。 - 引擎执行失败:查看平台适配器错误与原始响应;检查品牌匹配器与竞争品牌检测逻辑。 - CORS 问题:确认前端域名与请求头是否在允许范围内。 +- **新增** 代理框架问题:检查Redis连接、Agent注册状态、任务队列是否正常。 +- **新增** LLM服务问题:检查API密钥配置、提供商可用性、请求超时设置。 +- **新增** 工作流执行问题:检查YAML配置语法、依赖关系、变量引用是否正确。 - **中间件问题**:检查限流规则配置,确认健康检查路径是否被正确豁免;验证日志中间件的logger配置。 - **管理员权限**:确认用户 is_admin 字段,检查管理员路由的权限验证逻辑。 - **订阅状态**:检查用户套餐与订阅状态的一致性,验证订阅历史记录的查询逻辑。 -**更新** 新增中间件、管理员服务、订阅服务相关的故障排查指导。 +**更新** 新增代理框架、LLM服务和分布式发布系统的故障排查指导。 **章节来源** - [backend/app/api/deps.py:16-43](file://backend/app/api/deps.py#L16-L43) @@ -696,15 +1128,18 @@ ENGINE --> MODELS["models/*.py"] - [backend/app/workers/citation_engine.py:211-227](file://backend/app/workers/citation_engine.py#L211-L227) - [backend/app/middleware/rate_limit.py:34-83](file://backend/app/middleware/rate_limit.py#L34-L83) - [backend/app/middleware/logging_middleware.py:8-24](file://backend/app/middleware/logging_middleware.py#L8-L24) +- [backend/app/agent_framework/base.py:148-182](file://backend/app/agent_framework/base.py#L148-L182) +- [backend/app/workers/llm_adapter.py:141-218](file://backend/app/workers/llm_adapter.py#L141-L218) +- [backend/app/agent_framework/pipeline/loader.py:124-134](file://backend/app/agent_framework/pipeline/loader.py#L124-L134) ## 结论 -该架构以 FastAPI 为核心,结合异步数据库、定时任务与多平台适配器,形成高可用、可扩展的查询与引用检测系统。通过明确的分层与依赖注入,系统具备良好的可测试性与可维护性。新增的中间件系统提供了安全防护和性能监控能力,管理员服务增强了系统管理功能,订阅服务完善了商业化运营能力,报告服务提升了用户体验。建议在生产环境中完善日志与监控、接入缓存与告警,并持续优化索引与查询计划。 +该架构以 FastAPI 为核心,结合异步数据库、定时任务与多平台适配器,形成高可用、可扩展的查询与引用检测系统。通过明确的分层与依赖注入,系统具备良好的可测试性与可维护性。新增的代理框架、LLM服务集成、工作器系统扩展和分布式发布系统,显著增强了系统的智能化、自动化和企业级服务能力。系统现已支持复杂的AI内容生产工作流、多提供商的LLM集成、分布式任务调度和实时进度监控,为GEO平台的商业化运营奠定了坚实的技术基础。 -**更新** 本次更新显著增强了系统的功能完整性,包括安全防护、管理能力、商业运营和用户体验等方面。 +**更新** 本次更新大幅扩展了系统功能,新增代理框架、LLM服务集成、工作器系统扩展和分布式发布系统,形成了更加完整的企业级AI内容生产与管理平台。 ## 附录 - API 设计原则:统一前缀与标签、明确响应模型、一致的状态码与错误消息。 - 错误处理:在路由层捕获业务异常并转换为标准 HTTP 状态码;在依赖层统一 401 未授权。 - 响应格式:遵循 Pydantic 模型序列化,确保前后端契约一致。 - 架构决策背景:选择异步栈以提升 I/O 密集场景性能;APScheduler 简化定时任务编排;JWT 适合无状态认证场景;中间件系统提供安全防护和性能监控。 -- **新增功能背景**:中间件系统满足安全需求;管理员服务满足系统管理需求;订阅服务满足商业化需求;报告服务满足用户体验需求。 \ No newline at end of file +- **新增功能背景**:代理框架满足分布式任务调度需求;LLM服务满足AI能力集成需求;工作器系统扩展满足多平台适配需求;分布式发布系统满足复杂工作流编排需求。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/开发指南/开发指南.md b/.qoder/repowiki/zh/content/开发指南/开发指南.md index 2915315..3174235 100644 --- a/.qoder/repowiki/zh/content/开发指南/开发指南.md +++ b/.qoder/repowiki/zh/content/开发指南/开发指南.md @@ -18,22 +18,45 @@ - [backend/app/schemas/auth.py](file://backend/app/schemas/auth.py) - [backend/app/models/user.py](file://backend/app/models/user.py) - [README.md](file://README.md) +- [docs/03-development/coding-standards.md](file://docs/03-development/coding-standards.md) +- [docs/03-development/dev-guide.md](file://docs/03-development/dev-guide.md) +- [docs/05-deployment/deployment-guide.md](file://docs/05-deployment/deployment-guide.md) +- [docs/04-testing/test-strategy.md](file://docs/04-testing/test-strategy.md) +- [docs/03-development/tdd-workflow.md](file://docs/03-development/tdd-workflow.md) +- [docs/00-project/tech-stack.md](file://docs/00-project/tech-stack.md) +## 更新摘要 +**所做更改** +- 新增完整的代码规范文档,包含Python和TypeScript开发标准 +- 新增TDD测试驱动开发流程规范,定义RED-GREEN-REFACTOR循环 +- 新增开发指南文档,涵盖环境搭建和开发流程 +- 新增部署指南文档,定义多环境部署策略 +- 新增测试策略文档,建立四层测试金字塔 +- 新增技术栈说明文档,详细阐述各技术选型 +- 更新模块设计指南,增加Agent框架开发指导 +- 完善开发工具使用方法,包含调试和性能分析工具 + ## 目录 1. 引言 2. 项目结构 3. 核心组件 4. 架构总览 5. 详细组件分析 -6. 依赖分析 -7. 性能考虑 -8. 故障排查指南 -9. 结论 -10. 附录 +6. 代码规范与最佳实践 +7. 开发流程与工作流 +8. 开发工具使用方法 +9. 新功能开发指导原则 +10. 测试策略与实施 +11. 部署管理 +12. 常见问题与解决方案 +13. 结论 +14. 附录 ## 引言 -本开发指南面向GEO项目的开发者,旨在统一前后端代码规范与最佳实践,明确开发流程与工作流(包括分支策略、代码评审与版本发布),并提供开发工具使用方法(IDE配置、调试与性能分析、**Git部署自动化脚本**)、新功能开发指导原则(模块设计、接口定义与测试要求),以及常见问题的排查方案。本指南以仓库中现有实现为依据,确保内容可落地、可执行。 +本开发指南面向GEO项目的开发者,旨在统一前后端代码规范与最佳实践,明确开发流程与工作流(包括分支策略、代码评审与版本发布),并提供开发工具使用方法(IDE配置、调试与性能分析、Git部署自动化脚本)、新功能开发指导原则(模块设计、接口定义与测试要求),以及常见问题的排查方案。本指南以仓库中现有实现为依据,确保内容可落地、可执行。 + +**更新** 新增完整的开发文档体系,包括代码规范、开发流程、测试策略和部署管理等核心内容。 ## 项目结构 GEO采用前后端分离架构,后端基于FastAPI,前端基于Next.js,数据库使用PostgreSQL,缓存使用Redis,任务调度使用APScheduler,浏览器自动化使用Playwright。项目通过Docker与docker-compose进行容器化编排,便于本地开发与部署。 @@ -75,20 +98,20 @@ DC --> REDIS - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) - [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) **章节来源** - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) - [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) ## 核心组件 @@ -101,10 +124,10 @@ DC --> REDIS **章节来源** - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) - [frontend/tsconfig.json:1-27](file://frontend/tsconfig.json#L1-L27) -- [frontend/.eslintrc.json:1-4](file://frontend/.eslintrc.json#L1-L4) +- [frontend/.eslintrc.json:1-14](file://frontend/.eslintrc.json#L1-L14) - [frontend/tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) - [backend/alembic.ini:86-114](file://backend/alembic.ini#L86-L114) - [tests/conftest.py:1-71](file://tests/conftest.py#L1-L71) @@ -129,7 +152,7 @@ FastAPI --> Playwright **图表来源** - [backend/app/main.py:24-47](file://backend/app/main.py#L24-L47) -- [backend/app/config.py:7-13](file://backend/app/config.py#L7-L13) +- [backend/app/config.py:12-18](file://backend/app/config.py#L12-L18) - [backend/Dockerfile:31-33](file://backend/Dockerfile#L31-L33) - [docker-compose.yml:4-20](file://docker-compose.yml#L4-L20) - [docker-compose.yml:22-34](file://docker-compose.yml#L22-L34) @@ -238,7 +261,7 @@ SkipHooks --> Done **章节来源** - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) -- [backend/app/config.py:7-8](file://backend/app/config.py#L7-L8) +- [backend/app/config.py:12-13](file://backend/app/config.py#L12-L13) ### 前端工程化 - 构建与运行:dev/build/start/lint脚本由Next.js提供。 @@ -247,9 +270,9 @@ SkipHooks --> Done - Tailwind:按需扫描pages/components/app目录,启用动画插件。 **章节来源** -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) - [frontend/tsconfig.json:1-27](file://frontend/tsconfig.json#L1-L27) -- [frontend/.eslintrc.json:1-4](file://frontend/.eslintrc.json#L1-L4) +- [frontend/.eslintrc.json:1-14](file://frontend/.eslintrc.json#L1-L14) - [frontend/tailwind.config.ts:1-57](file://frontend/tailwind.config.ts#L1-L57) ### Git部署自动化脚本 @@ -286,219 +309,374 @@ SkipHooks --> Done **章节来源** - [README.md:1-3](file://README.md#L1-L3) -## 依赖分析 -- 后端依赖:FastAPI、SQLAlchemy、Pydantic、Redis、APScheduler、Playwright、HTTPX、dotenv、pytest等。 -- 前端依赖:Next.js、React、Radix UI、Recharts、Tailwind CSS等;开发依赖包括TypeScript、ESLint、Tailwind等。 -- 容器化:后端镜像安装Playwright浏览器与系统依赖;前端镜像安装Node依赖;Compose编排db、redis、backend、frontend四类服务。 -- **部署工具**:Git、Docker CLI、Docker Compose等部署相关工具。 +## 代码规范与最佳实践 -```mermaid -graph LR -subgraph "后端" -FastAPI["FastAPI"] -SQLA["SQLAlchemy"] -Pydantic["Pydantic"] -RedisDep["Redis"] -APS["APScheduler"] -PW["Playwright"] -HTTPX["HTTPX"] -DOTENV["python-dotenv"] -PyTest["pytest"] -end -subgraph "前端" -Next["Next.js"] -React["React"] -Radix["Radix UI"] -Recharts["Recharts"] -Tailwind["Tailwind CSS"] -TS["TypeScript"] -ESL["ESLint"] -end -subgraph "部署工具" -Git["Git"] -Docker["Docker CLI"] -DockerCompose["Docker Compose"] -PushScript["push_script.sh"] -end -FastAPI --> SQLA -FastAPI --> Pydantic -FastAPI --> RedisDep -FastAPI --> APS -FastAPI --> PW -FastAPI --> HTTPX -FastAPI --> DOTENV -Next --> React -Next --> Tailwind -Next --> Radix -Next --> Recharts -Next --> TS -Next --> ESL -Docker --> DockerCompose -Docker --> PushScript -Git --> PushScript -``` +### Python代码规范 +- **命名约定** + - 模块与类使用PascalCase(如:UserService、CitationDetector) + - 函数与变量使用snake_case(如:get_user_by_id、process_data) + - 常量使用UPPER_CASE(如:MAX_RETRY_COUNT、DEFAULT_TIMEOUT) + - 私有成员使用单下划线前缀(如:_internal_method) -**图表来源** -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) -- [frontend/package.json:11-38](file://frontend/package.json#L11-L38) -- [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) +- **代码格式化** + - 使用Black进行代码格式化,统一代码风格 + - Pydantic v2进行数据校验与配置管理 + - 字段约束与默认值清晰明确 + +- **类型注解** + - 严格使用类型注解,包括函数参数、返回值和变量声明 + - 使用Union、Optional等类型组合器处理可选类型 + - 利用Generic类型支持泛型编程 + +- **错误处理** + - 对外抛出HTTPException并设置合适的状态码与错误信息 + - 使用try-except捕获特定异常,避免裸except + - 实现统一的异常处理器 + +- **模块化设计** + - API、Schema、Model、Service分层清晰,职责单一 + - 配置通过Pydantic Settings从.env加载,区分开发与生产环境 **章节来源** -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) -- [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) +- [backend/app/config.py:9-46](file://backend/app/config.py#L9-L46) -## 性能考虑 -- 异步化:后端使用异步数据库驱动与异步HTTP客户端,减少阻塞,提升并发能力。 -- 缓存:Redis用于任务调度与会话等场景,建议在热点数据访问处引入缓存层。 -- 任务调度:APScheduler负责周期性任务,注意避免重复任务与资源泄漏,结合优雅停机逻辑。 -- 前端构建:严格模式与按需扫描Tailwind可降低包体与构建开销;生产构建建议开启压缩与Tree Shaking。 -- 数据库:合理索引与查询优化,避免N+1查询;批量写入与事务合并可减少往返次数。 -- **部署性能**:使用push_script.sh的增量构建功能,避免不必要的镜像重建;合理配置Docker构建缓存。 +### TypeScript/React代码规范 +- **命名约定** + - 接口与类型使用PascalCase(如:UserData、ApiResponse) + - 变量与函数使用camelCase(如:getUserData、processFormData) + - 枚举使用UPPER_CASE(如:UserRole.ADMIN) -## 故障排查指南 -- 启动失败(后端):检查数据库与Redis健康状态,确认连接字符串与端口映射正确;查看Uvicorn日志与容器重启策略。 -- 认证异常:核对JWT密钥与过期时间配置;确认请求头携带正确的Bearer Token;检查依赖覆盖与用户mock是否生效。 -- 数据迁移问题:检查Alembic日志级别与钩子配置;确认数据库URL与凭据;必要时手动回滚或修复迁移脚本。 -- 前端样式异常:确认Tailwind content扫描路径与组件目录一致;清理.next缓存后重新构建。 -- 测试失败:确认pytest会话注入后端路径;检查调度器mock与依赖覆盖;使用异步HTTP客户端发起请求。 -- **部署失败**:检查push_script.sh权限设置;确认Git配置与远程仓库访问权限;验证Docker守护进程状态;查看部署日志输出。 +- **类型系统** + - 严格模式开启,禁用输出JS + - 使用bundler解析模块,确保类型安全 + - 路径别名@/*映射根目录,简化导入路径 + +- **组件设计** + - 使用React Hooks管理状态和副作用 + - 实现受控组件模式,确保数据流清晰 + - 组件Props使用TypeScript接口定义 + +- **ESLint配置** + - 继承Next.js核心Web Vitals与TypeScript规则 + - 自定义规则:忽略未使用变量警告,支持下划线前缀 + +**章节来源** +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) +- [frontend/tsconfig.json:1-27](file://frontend/tsconfig.json#L1-L27) +- [frontend/.eslintrc.json:1-14](file://frontend/.eslintrc.json#L1-L14) + +### 注释规范 +- **Python文档字符串** + - 使用Google风格的docstring格式 + - 函数文档包含:参数说明、返回值、异常说明 + - 类文档包含:构造函数说明、主要方法列表 + +- **TypeScript JSDoc** + - 接口和类型使用JSDoc注释 + - 复杂函数添加详细说明和使用示例 + - 导出的公共API必须有完整注释 + +- **代码注释** + - 重要算法添加算法思路说明 + - 外部依赖添加版本和用途说明 + - 临时解决方案添加TODO注释 + +**章节来源** +- [docs/03-development/coding-standards.md:1-29](file://docs/03-development/coding-standards.md#L1-L29) + +## 开发流程与工作流 + +### Git分支策略 +- **主分支(main)**:保护分支,仅允许通过Pull Request合并 +- **功能分支(feature/*)**:开发新功能,完成后合并到develop +- **发布分支(release/x.y.z)**:用于预发布与回归测试 +- **热修复分支(hotfix/*)**:直接修改main分支并回放至develop + +### 代码评审流程 +- Pull Request必须包含变更说明、测试用例与性能影响评估 +- 至少一名Reviewer同意后方可合并 +- 评审关注点:代码质量、安全性、可维护性与兼容性 + +### 版本发布管理 +- **语义化版本控制**:小版本用于新增功能,补丁版本用于修复 +- **发布前检查**:更新CHANGELOG,运行全量测试,检查依赖安全漏洞 +- **发布后验证**:同步文档与环境配置,监控线上指标 + +**章节来源** +- [docs/03-development/dev-guide.md:1-32](file://docs/03-development/dev-guide.md#L1-L32) + +## 开发工具使用方法 + +### IDE配置 +- **VS Code**:安装Python与TypeScript扩展,启用ESLint与Prettier +- **前端**:启用TypeScript智能提示与ESLint实时检查;Tailwind IntelliSense增强CSS类提示 + +### 调试技巧 +- **后端**:使用Uvicorn的reload选项热重载;在FastAPI中设置调试日志级别 +- **前端**:使用Next.js dev模式热更新;在浏览器开发者工具中检查网络与状态 + +### 性能分析工具 +- **后端**:使用cProfile或py-spy分析CPU与内存;结合APScheduler监控任务耗时 +- **前端**:使用Chrome DevTools Performance面板分析渲染与网络 + +### 部署工具使用 +- **push_script.sh使用**:确保脚本具有执行权限,基本使用./push_script.sh +- **Docker部署**:使用docker-compose up -d启动服务,logs查看日志 + +**章节来源** +- [docs/03-development/dev-guide.md:1-32](file://docs/03-development/dev-guide.md#L1-L32) + +## 新功能开发指导原则 + +### 模块设计 +- 遵循"API-Service-Model"三层架构,保持关注点分离 +- 将业务逻辑封装在Service层,避免在API层直接操作数据库 + +### 接口定义 +- 使用Pydantic模型定义请求与响应结构,明确字段类型与约束 +- 对外暴露RESTful接口,遵循统一的前缀与标签组织路由 + +### 测试要求 +- **单元测试**:覆盖关键业务逻辑与边界条件 +- **集成测试**:使用pytest与AsyncClient发起HTTP请求,验证端到端流程 +- **Mock策略**:对调度器、外部服务与数据库进行合理Mock + +### 部署要求 +- 新功能开发完成后,使用push_script.sh进行部署测试 +- 确保所有环境变量正确配置,包括数据库连接、Redis配置等 + +**章节来源** +- [docs/03-development/dev-guide.md:1-32](file://docs/03-development/dev-guide.md#L1-L32) + +## 测试策略与实施 + +### TDD测试驱动开发 +**新增** GEO平台采用完整的TDD(测试驱动开发)流程: + +#### RED-GREEN-REFACTOR循环 +- **RED阶段**:编写失败测试,验证具体功能点 +- **GREEN阶段**:编写最少量生产代码使测试通过 +- **REFACTOR阶段**:优化代码结构、消除重复、提升可读性 + +#### 测试层次金字塔 +``` + ▲ + /│\ + / │ \ E2E 测试(端到端) + / │ \ 覆盖关键用户旅程 + /───┼───\ 占比:5% + / │ \ + /─────┼─────\ 集成测试 + / │ \ 模块间交互验证 + /───────┼───────\ 占比:15% + / │ \ + /─────────┼─────────\ 单元测试 + / │ \ 单个函数/类验证 + /───────────┼───────────\ 占比:60% + / │ \ + /─────────────┼─────────────\ Agent 测试 + / │ \ Agent 行为验证 + /───────────────┼───────────────\ 占比:20% + ─────────────────────────────────── +``` + +#### 单元测试(Unit Tests) +- **目标**:验证单个函数、类或方法的行为 +- **原则**:FIRST原则(Fast、Independent、Repeatable、Self-validating、Timely) +- **工具**:pytest + unittest.mock + +#### 集成测试(Integration Tests) +- **目标**:验证多个模块之间的交互是否正确 +- **范围**:数据库、缓存、消息队列等真实组件 +- **工具**:pytest + TestClient(FastAPI) + testcontainers + +#### E2E测试(End-to-End Tests) +- **目标**:模拟真实用户操作,验证完整业务流程 +- **工具**:Playwright(前端)+ pytest(后端 API) + +#### Agent测试(Agent Tests) +- **目标**:验证 AI Agent 的行为和输出质量 +- **特殊要求**:使用固定测试输入,验证输出结构和质量 + +**章节来源** +- [docs/03-development/tdd-workflow.md:1-583](file://docs/03-development/tdd-workflow.md#L1-L583) + +### 测试覆盖要求 +- **单元测试**:>= 80%覆盖率 +- **集成测试**:覆盖所有API端点 +- **E2E测试**:覆盖所有P0用户旅程 +- **Agent测试**:覆盖核心场景 + +### 测试数据管理 +- **Fixtures**:使用pytest.fixture管理测试数据 +- **工厂模式**:复杂对象使用工厂函数创建 +- **数据清理**:每个测试前后清理数据,失败时回滚 + +**章节来源** +- [docs/04-testing/test-strategy.md:1-33](file://docs/04-testing/test-strategy.md#L1-L33) + +## 部署管理 + +### 部署架构 +**新增** GEO平台支持多环境部署: + +#### 开发环境部署 +- 使用本地Docker Compose启动 +- 开发数据库和Redis实例 +- 支持热重载和调试模式 + +#### 测试环境部署 +- 使用独立的测试数据库 +- 配置测试专用的API密钥 +- 自动化测试流水线集成 + +#### 生产环境部署 +- 使用Nginx反向代理 +- 配置SSL证书和域名 +- 负载均衡和滚动更新 + +### 部署检查清单 +- **环境配置**:数据库连接、Redis配置、API密钥 +- **服务健康**:容器状态、端口映射、网络连通性 +- **数据迁移**:Alembic迁移执行、数据完整性检查 +- **安全配置**:JWT密钥、CORS配置、SSL证书 + +**章节来源** +- [docs/05-deployment/deployment-guide.md:1-32](file://docs/05-deployment/deployment-guide.md#L1-L32) + +## 常见问题与解决方案 + +### 数据库连接失败 +- 检查PostgreSQL容器健康状态与端口映射 +- 确认DATABASE_URL与凭据 + +### Redis连接失败 +- 检查Redis容器健康状态与端口映射 +- 确认REDIS_URL + +### Playwright无法启动浏览器 +- 确认Dockerfile中已安装Playwright浏览器与系统依赖 +- 检查PLAYWRIGHT_BROWSERS_PATH + +### CORS跨域问题 +- 核对CORS中间件配置的allow_origins与headers +- 确保前端域名与端口匹配 + +### JWT认证失败 +- 检查JWT_SECRET与过期时间 +- 确认请求头Authorization格式为Bearer Token + +### 测试失败排查 +- **单元测试**:检查Mock配置和依赖注入 +- **集成测试**:验证数据库连接和事务处理 +- **E2E测试**:检查浏览器自动化和页面元素定位 + +### 性能问题诊断 +- **后端**:使用cProfile分析CPU使用率,检查数据库查询 +- **前端**:使用Chrome DevTools分析渲染性能,检查组件重渲染 **章节来源** - [docker-compose.yml:4-34](file://docker-compose.yml#L4-L34) -- [backend/app/config.py:7-13](file://backend/app/config.py#L7-L13) +- [backend/app/config.py:12-18](file://backend/app/config.py#L12-L18) - [tests/conftest.py:19-50](file://tests/conftest.py#L19-L50) - [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150) - [frontend/tailwind.config.ts:5-9](file://frontend/tailwind.config.ts#L5-L9) ## 结论 -本指南基于仓库现有实现,给出了统一的代码规范、开发流程与工具使用建议。建议在后续迭代中补充更详细的Git分支策略、代码评审清单与发布流程文档,并持续完善测试覆盖率与性能监控体系。**新增的部署脚本push_script.sh显著提升了开发者的部署效率,建议在团队内部推广使用并定期更新其功能特性。** +本指南基于仓库现有实现,建立了完整的开发文档体系,包括代码规范、开发流程、测试策略和部署管理等核心内容。建议在后续迭代中持续完善文档内容,补充更详细的Git分支策略、代码评审清单与发布流程文档,并持续完善测试覆盖率与性能监控体系。 + +**更新** 新增的开发文档体系显著提升了项目的规范化程度,为团队协作和项目维护奠定了坚实基础。 ## 附录 -### 代码规范与最佳实践 +### 技术栈说明 +**新增** GEO平台采用现代化技术栈: -- **Python(后端)** - - 使用Pydantic v2进行数据校验与配置管理,字段约束与默认值清晰明确。 - - 异步编程:优先使用异步数据库与HTTP客户端,避免阻塞操作。 - - 错误处理:对外抛出HTTPException并设置合适的状态码与错误信息。 - - 模块化:API、Schema、Model、Service分层清晰,职责单一。 - - 配置:通过Pydantic Settings从.env加载配置,区分开发与生产环境。 +#### 前端技术栈 +- **Next.js 14**:React框架,支持SSR和静态生成 +- **TypeScript**:强类型语言,提升代码质量和开发体验 +- **Tailwind CSS**:原子化CSS框架,快速构建UI界面 +- **shadcn/ui**:高质量组件库,支持主题定制 +- **NextAuth.js**:认证解决方案,支持多种登录方式 -- **TypeScript(前端)** - - 严格模式开启,禁用输出JS,使用bundler解析模块,确保类型安全。 - - ESLint规则继承Next.js核心Web Vitals与TypeScript默认规则,保持一致性。 - - Tailwind按需扫描组件与页面目录,减少CSS体积;启用动画插件提升交互体验。 - - 路径别名@/*映射根目录,简化导入路径。 +#### 后端技术栈 +- **FastAPI**:高性能异步Web框架 +- **Python 3.12**:类型提示最佳实践 +- **SQLAlchemy 2.0**:ORM对象关系映射 +- **Alembic**:数据库迁移管理 +- **Celery**:异步任务队列(可选) +- **Redis**:缓存与消息代理 -- **命名约定** - - Python:模块与类使用PascalCase;函数与变量使用snake_case;常量使用UPPER_CASE。 - - TypeScript:接口与类型使用PascalCase;变量与函数使用camelCase;枚举使用UPPER_CASE。 +#### AI Agent技术栈 +- **Agent框架**:可扩展的AI代理框架 +- **LLM模型**:支持多种大语言模型 +- **提示工程**:结构化的提示模板管理 +- **向量数据库**:可选的向量相似度检索 -- **部署脚本规范** - - 使用push_script.sh进行标准化部署,避免手动操作导致的不一致。 - - 遵循语义化版本控制,合理选择版本类型(patch/minor/major)。 - - 在团队内统一部署流程,确保所有成员使用相同的部署脚本参数。 - -### 开发流程与工作流 - -- **Git分支策略(建议)** - - 主分支:保护分支,仅允许通过PR合并。 - - 功能分支:feature/xxx,完成后合并到develop。 - - 发布分支:release/x.y.z,用于预发布与回归测试。 - - 热修复分支:hotfix/xxx,直接修改主分支并回放至develop。 - -- **代码评审(建议)** - - PR必须包含变更说明、测试用例与性能影响评估。 - - 至少一名Reviewer同意后方可合并。 - - 评审关注点:代码质量、安全性、可维护性与兼容性。 - -- **版本发布管理(建议)** - - 语义化版本:小版本用于新增功能,补丁版本用于修复。 - - 发布前:更新CHANGELOG,运行全量测试,检查依赖安全漏洞。 - - 发布后:同步文档与环境配置,监控线上指标。 - - **使用push_script.sh自动化版本标记与发布流程**。 - -### 开发工具使用方法 - -- **IDE配置(建议)** - - VS Code:安装Python与TypeScript扩展,启用ESLint与Prettier;配置Python解释器为虚拟环境。 - - 前端:启用TypeScript智能提示与ESLint实时检查;Tailwind IntelliSense增强CSS类提示。 - -- **调试技巧** - - 后端:使用Uvicorn的reload选项热重载;在FastAPI中设置调试日志级别;利用依赖注入覆盖与mock替换真实外部服务。 - - 前端:使用Next.js dev模式热更新;在浏览器开发者工具中检查网络与状态;Tailwind调试辅助类辅助布局。 - -- **性能分析工具(建议)** - - 后端:使用cProfile或py-spy分析CPU与内存;结合APScheduler监控任务耗时。 - - 前端:使用Chrome DevTools Performance面板分析渲染与网络;使用Lighthouse评估SEO与可访问性。 - -- **部署工具使用方法** - - **push_script.sh使用**: - - 确保脚本具有执行权限:chmod +x push_script.sh - - 基本使用:./push_script.sh - - 指定版本类型:./push_script.sh patch/minor/major - - 指定环境:./push_script.sh -e development/production - - 查看帮助:./push_script.sh -h - - **Docker部署**: - - 使用docker-compose up -d启动服务 - - 使用docker-compose down停止服务 - - 使用docker-compose logs查看日志 - -### 新功能开发指导原则 - -- **模块设计** - - 遵循"API-Service-Model"三层架构,保持关注点分离。 - - 将业务逻辑封装在Service层,避免在API层直接操作数据库。 - -- **接口定义** - - 使用Pydantic模型定义请求与响应结构,明确字段类型与约束。 - - 对外暴露RESTful接口,遵循统一的前缀与标签组织路由。 - -- **测试要求** - - 单元测试:覆盖关键业务逻辑与边界条件。 - - 集成测试:使用pytest与AsyncClient发起HTTP请求,验证端到端流程。 - - Mock策略:对调度器、外部服务与数据库进行合理Mock,保证测试稳定性。 - -- **部署要求** - - 新功能开发完成后,使用push_script.sh进行部署测试。 - - 确保所有环境变量正确配置,包括数据库连接、Redis配置等。 - - 部署前进行完整的功能测试和性能测试。 - -### 常见问题与解决方案 - -- **数据库连接失败** - - 检查PostgreSQL容器健康状态与端口映射;确认DATABASE_URL与凭据。 - -- **Redis连接失败** - - 检查Redis容器健康状态与端口映射;确认REDIS_URL。 - -- **Playwright无法启动浏览器** - - 确认Dockerfile中已安装Playwright浏览器与系统依赖;检查PLAYWRIGHT_BROWSERS_PATH。 - -- **CORS跨域问题** - - 核对CORS中间件配置的allow_origins与headers;确保前端域名与端口匹配。 - -- **JWT认证失败** - - 检查JWT_SECRET与过期时间;确认请求头Authorization格式为Bearer Token。 - -- **部署脚本执行失败** - - 检查脚本权限:chmod +x push_script.sh - - 确认Git配置:git config --global user.name 和 git config --global user.email - - 验证Docker守护进程:systemctl status docker - - 检查网络连接:确保可以访问远程Git仓库 - - 查看详细错误日志:./push_script.sh -v - -- **Docker构建失败** - - 清理Docker缓存:docker system prune - - 检查Dockerfile语法:docker build --no-cache -t geo-app . - - 确认网络连接:代理设置或防火墙配置 - - 检查磁盘空间:清理不必要的镜像和容器 +#### 基础设施技术栈 +- **Docker**:容器化部署 +- **Docker Compose**:服务编排 +- **PostgreSQL**:关系型数据库 +- **Redis集群**:生产环境缓存 +- **Nginx**:反向代理与负载均衡 +- **日志收集**:集中化日志管理 **章节来源** -- [backend/app/main.py:30-36](file://backend/app/main.py#L30-L36) -- [backend/app/config.py:9-13](file://backend/app/config.py#L9-L13) -- [backend/Dockerfile:31-33](file://backend/Dockerfile#L31-L33) -- [docker-compose.yml:4-20](file://docker-compose.yml#L4-L20) -- [docker-compose.yml:22-34](file://docker-compose.yml#L22-L34) -- [README.md:1-3](file://README.md#L1-L3) \ No newline at end of file +- [docs/00-project/tech-stack.md:1-71](file://docs/00-project/tech-stack.md#L1-L71) + +### 模块指南 +**新增** 为不同模块提供专门的开发指导: + +#### Agent框架开发 +- **Agent设计原则**:单一职责、可扩展性、可测试性 +- **提示工程**:结构化提示模板设计 +- **模型集成**:统一的LLM调用接口 +- **错误处理**:健壮的异常处理机制 + +#### API开发规范 +- **路由设计**:RESTful API设计原则 +- **错误处理**:统一的错误响应格式 +- **文档生成**:OpenAPI规范自动生成 +- **版本控制**:API版本管理策略 + +#### 数据模型设计 +- **ORM映射**:SQLAlchemy模型定义 +- **关系设计**:实体关系建模 +- **索引优化**:数据库性能优化 +- **数据迁移**:版本化的数据库变更 + +**章节来源** +- [docs/03-development/module-guides/](file://docs/03-development/module-guides/) + +### 开发环境搭建 +**新增** 详细的环境搭建步骤: + +#### 系统要求 +- **操作系统**:Windows 10+/macOS 10.15+/Linux Ubuntu 18.04+ +- **内存**:至少8GB RAM(推荐16GB+) +- **存储**:至少20GB可用空间 +- **网络**:稳定的互联网连接 + +#### 开发工具 +- **Python**:3.12+(推荐使用pyenv管理版本) +- **Node.js**:18.x LTS版本 +- **Docker**:20.10+(包含Docker Compose) +- **Git**:2.0+ +- **IDE**:VS Code + 推荐插件 + +#### 环境变量配置 +- **数据库连接**:DATABASE_URL +- **Redis配置**:REDIS_URL +- **JWT配置**:JWT_SECRET、JWT_EXPIRE_HOURS +- **LLM配置**:各种AI平台API密钥 + +#### 本地开发工作流 +1. 克隆仓库并安装依赖 +2. 配置环境变量文件 +3. 启动Docker容器 +4. 初始化数据库 +5. 开始开发和测试 + +**章节来源** +- [docs/03-development/dev-guide.md:1-32](file://docs/03-development/dev-guide.md#L1-L32) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/扩展与定制/扩展与定制.md b/.qoder/repowiki/zh/content/扩展与定制/扩展与定制.md index 32f82ff..1b3d7ef 100644 --- a/.qoder/repowiki/zh/content/扩展与定制/扩展与定制.md +++ b/.qoder/repowiki/zh/content/扩展与定制/扩展与定制.md @@ -8,6 +8,7 @@ - [backend/app/api/queries.py](file://backend/app/api/queries.py) - [backend/app/api/reports.py](file://backend/app/api/reports.py) - [backend/app/api/citations.py](file://backend/app/api/citations.py) +- [backend/app/api/agents.py](file://backend/app/api/agents.py) - [backend/app/models/query.py](file://backend/app/models/query.py) - [backend/app/schemas/query.py](file://backend/app/schemas/query.py) - [backend/app/workers/scheduler.py](file://backend/app/workers/scheduler.py) @@ -28,13 +29,29 @@ - [frontend/app/layout.tsx](file://frontend/app/layout.tsx) - [frontend/components/providers.tsx](file://frontend/components/providers.tsx) - [frontend/lib/api.ts](file://frontend/lib/api.ts) +- [frontend/lib/api/agents.ts](file://frontend/lib/api/agents.ts) - [frontend/package.json](file://frontend/package.json) - [docker-compose.yml](file://docker-compose.yml) - [backend/Dockerfile](file://backend/Dockerfile) - [frontend/Dockerfile](file://frontend/Dockerfile) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py) +- [backend/app/agent_framework/registry.py](file://backend/app/agent_framework/registry.py) +- [backend/app/agent_framework/config_manager.py](file://backend/app/agent_framework/config_manager.py) +- [backend/app/agent_framework/dispatcher.py](file://backend/app/agent_framework/dispatcher.py) +- [backend/app/agent_framework/protocol.py](file://backend/app/agent_framework/protocol.py) +- [backend/app/agent_framework/pipeline/engine.py](file://backend/app/agent_framework/pipeline/engine.py) +- [backend/app/models/agent.py](file://backend/app/models/agent.py) +- [.env.example](file://.env.example) +## 更新摘要 +**所做更改** +- 新增了智能体框架扩展指南,包括 Agent 注册中心、配置管理和任务调度 +- 扩展了前端 API 封装,新增 agents 模块的完整实现 +- 更新了配置定制方法,增加了 LLM 提供商配置和 AI 平台集成 +- 完善了第三方集成方案,涵盖智能体系统、Redis 集成和管道编排 +- 增加了系统定制化案例研究和实施建议 + ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) @@ -48,18 +65,22 @@ 10. [附录](#附录) ## 简介 -本文件面向需要对 GEO 平台进行扩展与定制的工程师与产品团队,系统性阐述后端 API 扩展、前端页面扩展、数据模型扩展、配置定制、第三方集成(AI 平台、数据库、认证)以及插件化扩展的最佳实践。文档同时提供可落地的实施建议与案例研究,帮助快速实现业务定制化目标。 +本文件面向需要对 GEO 平台进行扩展与定制的工程师与产品团队,系统性阐述后端 API 扩展、前端页面扩展、数据模型扩展、配置定制、第三方集成(AI 平台、数据库、认证)以及智能体框架扩展的最佳实践。文档同时提供可落地的实施建议与案例研究,帮助快速实现业务定制化目标。 + +**更新** 本次更新重点加强了智能体框架的扩展能力,新增了完整的 Agent 管理、配置热更新、任务调度和管道编排功能。 ## 项目结构 GEO 采用前后端分离架构: - 后端基于 FastAPI,提供 REST API;通过 Alembic 管理数据库迁移;使用 SQLAlchemy ORM 定义模型;APScheduler 实现定时任务;Playwright 支持 AI 平台网页抓取。 - 前端基于 Next.js 14,使用 TypeScript、TailwindCSS、Radix UI 组件库;通过自定义 API 封装层与后端交互;NextAuth v4 提供会话管理。 +- **新增** 智能体框架支持,包括 Agent 注册中心、配置管理、任务调度和管道编排。 ```mermaid graph TB subgraph "前端" FE_APP["Next.js 应用
路由与页面"] FE_LIB["API 封装
lib/api.ts"] +FE_LIB_AGENTS["智能体API
lib/api/agents.ts"] FE_PROV["会话提供者
components/providers.tsx"] end subgraph "后端" @@ -68,51 +89,69 @@ BE_ROUTER_AUTH["认证路由
app/api/auth.py"] BE_ROUTER_QUERIES["查询路由
app/api/queries.py"] BE_ROUTER_CITATIONS["引用路由
app/api/citations.py"] BE_ROUTER_REPORTS["报告路由
app/api/reports.py"] +BE_ROUTER_AGENTS["智能体路由
app/api/agents.py"] BE_SCHED["调度器
app/workers/scheduler.py"] BE_PLAT_BASE["平台适配器基类
app/workers/platforms/base.py"] BE_PLAT_KIMI["Kimi 适配器
app/workers/platforms/kimi.py"] BE_PLAT_WENXIN["文心一言适配器
app/workers/platforms/wenxin.py"] BE_DB["数据库与模型
app/database.py + models/*"] +BE_AGENT_REGISTRY["Agent注册中心
agent_framework/registry.py"] +BE_AGENT_CONFIG["配置管理
agent_framework/config_manager.py"] +BE_AGENT_DISPATCH["任务调度
agent_framework/dispatcher.py"] +BE_AGENT_PIPELINE["管道引擎
agent_framework/pipeline/engine.py"] end FE_APP --> FE_LIB FE_LIB --> BE_MAIN +FE_LIB_AGENTS --> BE_ROUTER_AGENTS BE_MAIN --> BE_ROUTER_AUTH BE_MAIN --> BE_ROUTER_QUERIES BE_MAIN --> BE_ROUTER_CITATIONS BE_MAIN --> BE_ROUTER_REPORTS +BE_MAIN --> BE_ROUTER_AGENTS BE_MAIN --> BE_SCHED BE_SCHED --> BE_PLAT_BASE BE_PLAT_BASE --> BE_PLAT_KIMI BE_PLAT_BASE --> BE_PLAT_WENXIN BE_MAIN --> BE_DB +BE_ROUTER_AGENTS --> BE_AGENT_REGISTRY +BE_ROUTER_AGENTS --> BE_AGENT_CONFIG +BE_ROUTER_AGENTS --> BE_AGENT_DISPATCH +BE_AGENT_DISPATCH --> BE_AGENT_PIPELINE ``` -图表来源 +**图表来源** - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) - [frontend/lib/api.ts:1-58](file://frontend/lib/api.ts#L1-L58) +- [frontend/lib/api/agents.ts:1-57](file://frontend/lib/api/agents.ts#L1-L57) - [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/platforms/kimi.py:1-206](file://backend/app/workers/platforms/kimi.py#L1-L206) - [backend/app/workers/platforms/wenxin.py:1-205](file://backend/app/workers/platforms/wenxin.py#L1-L205) - [backend/app/database.py](file://backend/app/database.py) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/config_manager.py:1-191](file://backend/app/agent_framework/config_manager.py#L1-L191) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-376](file://backend/app/agent_framework/pipeline/engine.py#L1-L376) -章节来源 +**章节来源** - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) - [frontend/app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [frontend/components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) ## 核心组件 -- API 层:认证、查询词、引用数据、报告导出等模块化路由,统一挂载于主应用。 -- 服务层:封装业务逻辑,如用户认证、查询 CRUD、引用处理等。 -- 数据层:SQLAlchemy 模型与 Pydantic Schema,定义实体与请求/响应结构。 -- 工作器与调度:APScheduler 驱动定时任务,CitationEngine 协调平台适配器执行查询。 -- 前端:Next.js 页面与组件,通过 lib/api.ts 统一访问后端接口;NextAuth 提供会话状态。 +- API 层:认证、查询词、引用数据、报告导出、**新增**智能体管理等模块化路由,统一挂载于主应用。 +- 服务层:封装业务逻辑,如用户认证、查询 CRUD、引用处理、**新增**智能体配置管理等。 +- 数据层:SQLAlchemy 模型与 Pydantic Schema,定义实体与请求/响应结构,**新增**智能体相关模型。 +- 工作器与调度:APScheduler 驱动定时任务,CitationEngine 协调平台适配器执行查询,**新增**智能体任务调度。 +- 前端:Next.js 页面与组件,通过 lib/api.ts 统一访问后端接口,**新增**智能体 API 封装。 +- **新增** 智能体框架:Agent 注册中心、配置管理、任务调度和管道编排系统。 -章节来源 +**章节来源** - [backend/app/api/auth.py:1-43](file://backend/app/api/auth.py#L1-L43) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) - [backend/app/api/citations.py](file://backend/app/api/citations.py) - [backend/app/api/reports.py](file://backend/app/api/reports.py) +- [backend/app/api/agents.py:1-299](file://backend/app/api/agents.py#L1-L299) - [backend/app/services/auth.py](file://backend/app/services/auth.py) - [backend/app/services/query.py](file://backend/app/services/query.py) - [backend/app/services/citation.py](file://backend/app/services/citation.py) @@ -120,9 +159,10 @@ BE_MAIN --> BE_DB - [backend/app/schemas/query.py:1-94](file://backend/app/schemas/query.py#L1-L94) - [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) - [frontend/lib/api.ts:1-58](file://frontend/lib/api.ts#L1-L58) +- [frontend/lib/api/agents.ts:1-57](file://frontend/lib/api/agents.ts#L1-L57) ## 架构总览 -下图展示从浏览器到后端 API、数据库与外部 AI 平台的完整链路: +下图展示从浏览器到后端 API、数据库与外部 AI 平台的完整链路,包括新增的智能体框架: ```mermaid sequenceDiagram @@ -134,9 +174,12 @@ participant DB as "数据库" participant Scheduler as "调度器" participant Engine as "CitationEngine" participant Plat as "平台适配器" +participant AgentFramework as "智能体框架" Browser->>Frontend : 用户操作 Frontend->>API : 发起 HTTP 请求 API->>Svc : 路由分发与校验 +svc->>AgentFramework : 智能体管理请求 +AgentFramework->>DB : 读写智能体配置 Svc->>DB : 读写数据 DB-->>Svc : 返回结果 Svc-->>API : 业务结果 @@ -148,13 +191,17 @@ Plat-->>Engine : 返回原始响应 Engine->>DB : 写入引用记录 ``` -图表来源 +**图表来源** - [frontend/lib/api.ts:1-58](file://frontend/lib/api.ts#L1-L58) +- [frontend/lib/api/agents.ts:1-57](file://frontend/lib/api/agents.ts#L1-L57) - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) - [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/platforms/kimi.py:1-206](file://backend/app/workers/platforms/kimi.py#L1-L206) - [backend/app/workers/platforms/wenxin.py:1-205](file://backend/app/workers/platforms/wenxin.py#L1-L205) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/config_manager.py:1-191](file://backend/app/agent_framework/config_manager.py#L1-L191) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) ## 详细组件分析 @@ -169,6 +216,7 @@ Engine->>DB : 写入引用记录 - 示例参考路径 - [认证路由示例:1-43](file://backend/app/api/auth.py#L1-L43) - [查询路由示例:1-86](file://backend/app/api/queries.py#L1-L86) + - [智能体路由示例:1-299](file://backend/app/api/agents.py#L1-L299) - [主应用挂载示例:38-42](file://backend/app/main.py#L38-L42) - [服务层示例](file://backend/app/services/query.py) - [Schema 示例:1-94](file://backend/app/schemas/query.py#L1-L94) @@ -186,10 +234,11 @@ Alembic --> Test["编写单元测试"] Test --> End(["完成"]) ``` -章节来源 +**章节来源** - [backend/app/main.py:38-42](file://backend/app/main.py#L38-L42) - [backend/app/api/auth.py:1-43](file://backend/app/api/auth.py#L1-L43) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) +- [backend/app/api/agents.py:1-299](file://backend/app/api/agents.py#L1-L299) - [backend/app/schemas/query.py:1-94](file://backend/app/schemas/query.py#L1-L94) - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) @@ -200,6 +249,7 @@ Test --> End(["完成"]) - 在 components/ui 下新增或复用 UI 组件,保持一致的设计语言。 - API 调用 - 在 frontend/lib/api.ts 中新增方法,遵循现有命名与错误处理模式。 + - **新增** 在 frontend/lib/api/agents.ts 中新增智能体相关 API 方法。 - 在页面中通过 hooks 或直接调用 api.* 方法获取数据。 - 会话与权限 - 使用 frontend/components/providers.tsx 包裹应用,确保 NextAuth 会话可用。 @@ -210,13 +260,15 @@ flowchart TD NewPage["新增页面
frontend/app/(group)/new/page.tsx"] --> Layout["布局与 Providers
frontend/app/layout.tsx"] Layout --> UI["UI 组件
frontend/components/ui/*"] UI --> API["API 封装
frontend/lib/api.ts"] -API --> Backend["后端 API
backend/app/api/*"] +API --> AgentsAPI["智能体API
frontend/lib/api/agents.ts"] +AgentsAPI --> Backend["后端 API
backend/app/api/*"] ``` -章节来源 +**章节来源** - [frontend/app/layout.tsx:1-37](file://frontend/app/layout.tsx#L1-L37) - [frontend/components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [frontend/lib/api.ts:1-58](file://frontend/lib/api.ts#L1-L58) +- [frontend/lib/api/agents.ts:1-57](file://frontend/lib/api/agents.ts#L1-L57) ### 数据模型扩展指南 - 字段与约束 @@ -262,16 +314,37 @@ string platform text raw_response timestamp created_at } +AGENT_REGISTRY { +uuid id PK +string name UK +string agent_type +string status +jsonb capabilities +timestamp last_heartbeat +timestamp created_at +timestamp updated_at +} +AGENT_CONFIGS { +uuid id PK +uuid agent_id FK +string config_key +jsonb config_value +uuid updated_by FK +timestamp updated_at +} QUERIES ||--o{ CITATION_RECORDS : "包含" USERS ||--o{ QUERIES : "拥有" +AGENT_REGISTRY ||--o{ AGENT_CONFIGS : "包含" ``` -图表来源 +**图表来源** - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) +- [backend/app/models/agent.py:1-206](file://backend/app/models/agent.py#L1-L206) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py) -章节来源 +**章节来源** - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) +- [backend/app/models/agent.py:1-206](file://backend/app/models/agent.py#L1-L206) - [backend/app/schemas/query.py:1-94](file://backend/app/schemas/query.py#L1-L94) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py) @@ -279,19 +352,22 @@ USERS ||--o{ QUERIES : "拥有" - 环境变量 - 通过 app/config.py 的 Settings 类集中管理,支持 .env 文件覆盖。 - 关键配置项包括数据库连接、Redis、JWT 密钥与过期时间、Playwright 浏览器路径、第三方平台密钥等。 + - **新增** LLM 提供商配置,包括默认提供商、模型选择和 API 密钥管理。 - 功能开关与性能参数 - 平台列表、频率策略、状态枚举在 Schema 中集中校验,便于扩展与限制。 - 调度周期(每小时)可在 app/workers/scheduler.py 中调整。 - 前端 NEXT_PUBLIC_API_URL 控制后端域名,lib/api.ts 中统一拼接。 + - **新增** 智能体框架配置,包括 Redis URL 和心跳超时设置。 - 建议 - 生产环境务必替换默认密钥与数据库密码。 - 将敏感信息放入 .env 并加入 .gitignore。 -章节来源 -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +**章节来源** +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/app/schemas/query.py:6-8](file://backend/app/schemas/query.py#L6-L8) - [backend/app/workers/scheduler.py:32-38](file://backend/app/workers/scheduler.py#L32-L38) - [frontend/lib/api.ts:1](file://frontend/lib/api.ts#L1) +- [.env.example:1-35](file://.env.example#L1-L35) ### 第三方集成扩展指南 @@ -325,12 +401,12 @@ BasePlatformAdapter <|-- KimiAdapter BasePlatformAdapter <|-- WenxinAdapter ``` -图表来源 +**图表来源** - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/platforms/kimi.py:1-206](file://backend/app/workers/platforms/kimi.py#L1-L206) - [backend/app/workers/platforms/wenxin.py:1-205](file://backend/app/workers/platforms/wenxin.py#L1-L205) -章节来源 +**章节来源** - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/platforms/kimi.py:1-206](file://backend/app/workers/platforms/kimi.py#L1-L206) - [backend/app/workers/platforms/wenxin.py:1-205](file://backend/app/workers/platforms/wenxin.py#L1-L205) @@ -343,7 +419,7 @@ BasePlatformAdapter <|-- WenxinAdapter - 在 requirements.txt 中替换驱动包。 - 重新生成/更新 Alembic 迁移以适配新方言。 -章节来源 +**章节来源** - [backend/app/database.py](file://backend/app/database.py) - [backend/app/config.py:7](file://backend/app/config.py#L7) - [backend/requirements.txt:5-8](file://backend/requirements.txt#L5-L8) @@ -357,26 +433,91 @@ BasePlatformAdapter <|-- WenxinAdapter - 保持 Authorization 头格式与后端解析一致。 - 在 app/api/deps.py 中的依赖注入中校验用户身份。 -章节来源 +**章节来源** - [backend/app/services/auth.py](file://backend/app/services/auth.py) - [frontend/components/providers.tsx:1-9](file://frontend/components/providers.tsx#L1-L9) - [frontend/lib/api.ts:3-21](file://frontend/lib/api.ts#L3-L21) - [backend/app/api/deps.py](file://backend/app/api/deps.py) +#### 智能体框架集成 +- Agent 注册中心 + - 通过 AgentRegistry 管理 Agent 的注册、发现与状态。 + - 支持心跳检测与自动离线标记。 +- 配置管理 + - AgentConfigManager 支持配置的热更新与批量修改。 + - 提供配置历史查询功能。 +- 任务调度 + - TaskDispatcher 通过 Redis Queue 实现任务分发。 + - 支持任务取消、状态查询和日志记录。 +- 管道编排 + - PipelineEngine 支持 YAML 定义的多阶段任务编排。 + - 实现拓扑排序、变量传递和条件执行。 + +```mermaid +classDiagram +class AgentRegistry { ++register(capability, endpoint) str ++unregister(agent_name) ++update_heartbeat(agent_name) ++get_agent(agent_name) dict ++list_agents(agent_type, status) list ++get_available_agent(task_type) str ++check_health() +} +class AgentConfigManager { ++get_config(agent_name) dict ++set_config(agent_name, key, value, updated_by) ++bulk_update_config(agent_name, configs, updated_by) ++get_config_history(agent_name, key) list +} +class TaskDispatcher { ++dispatch(task, organization_id, created_by) str ++cancel_task(task_id) ++get_task_status(task_id) dict ++handle_result(result) ++handle_progress(progress) ++retry_failed_tasks(max_retries) +} +class PipelineEngine { ++execute(pipeline, context) PipelineResult ++_topological_sort(stages) list ++dry_run_stage(stage, resolved_inputs) StageResult +} +AgentRegistry <.. TaskDispatcher : "任务分配" +AgentConfigManager <.. TaskDispatcher : "配置管理" +TaskDispatcher <.. PipelineEngine : "任务执行" +``` + +**图表来源** +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/config_manager.py:1-191](file://backend/app/agent_framework/config_manager.py#L1-L191) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-376](file://backend/app/agent_framework/pipeline/engine.py#L1-L376) + +**章节来源** +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/config_manager.py:1-191](file://backend/app/agent_framework/config_manager.py#L1-L191) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/agent_framework/pipeline/engine.py:1-376](file://backend/app/agent_framework/pipeline/engine.py#L1-L376) + ### 插件系统使用指南与最佳实践 - 插件化思路 - - 平台适配器采用“插件”式扩展:通过继承基类与工厂/映射注册,实现多平台并行。 - - 调度器与 CitationEngine 作为“核心引擎”,通过适配器接口解耦平台差异。 + - 平台适配器采用"插件"式扩展:通过继承基类与工厂/映射注册,实现多平台并行。 + - 调度器与 CitationEngine 作为"核心引擎",通过适配器接口解耦平台差异。 + - **新增** 智能体框架采用注册中心模式,支持动态 Agent 注册与发现。 - 最佳实践 - 明确职责边界:路由负责协议与鉴权,服务层负责业务规则,模型负责数据结构。 - 统一错误处理:前端统一捕获 HTTP 错误并提示;后端抛出明确异常码与消息。 - 可观测性:为关键流程增加日志与指标,便于定位问题。 - 安全:严格校验输入、最小权限原则、HTTPS 传输、密钥轮换。 + - **新增** 智能体安全:验证 Agent 能力声明,限制并发执行,监控心跳状态。 -章节来源 +**章节来源** - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) - [frontend/lib/api.ts:16-21](file://frontend/lib/api.ts#L16-L21) +- [backend/app/agent_framework/registry.py:1-219](file://backend/app/agent_framework/registry.py#L1-L219) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) ## 依赖分析 - 后端依赖 @@ -387,6 +528,7 @@ BasePlatformAdapter <|-- WenxinAdapter - 任务调度:APScheduler - 浏览器自动化:Playwright - HTTP 客户端:httpx + - **新增** 智能体框架:Redis async(aioredis)、SQLAlchemy JSONB - 前端依赖 - 框架与 UI:Next.js + Radix UI + TailwindCSS - 认证:NextAuth v4 @@ -403,6 +545,7 @@ J["python-jose/passlib"] R["Redis/APScheduler"] PW["Playwright"] H["httpx/python-dotenv"] +AIO["aioredis/sqlalchemy-jsonb"] end subgraph "前端依赖" N["Next.js"] @@ -412,26 +555,33 @@ RC["Recharts"] end ``` -图表来源 +**图表来源** - [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) - [frontend/package.json:11-27](file://frontend/package.json#L11-L27) -章节来源 +**章节来源** - [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) - [frontend/package.json:11-27](file://frontend/package.json#L11-L27) ## 性能考虑 - 数据库 - 为高频查询字段建立索引;避免 N+1 查询;使用分页参数限制单页规模。 + - **新增** 智能体相关表建立复合索引,优化查询性能。 - API - 合理设置分页参数(skip/limit),避免一次性返回大量数据。 - 对热点接口启用缓存(如 Redis)减少重复计算。 + - **新增** 智能体配置缓存,减少频繁查询数据库。 - 定时任务 - 调度周期可根据业务需求调整;在高负载时降低频率或增加并发控制。 - 浏览器自动化 - Playwright 启动成本较高,尽量复用上下文;失败重试与超时控制要合理设置。 - 前端 - 按需加载页面与组件;减少不必要的 re-render;利用浏览器缓存与静态资源优化。 + - **新增** 智能体状态管理,避免频繁重新获取配置。 +- **新增** 智能体框架性能 + - Redis 连接池管理,避免频繁创建连接。 + - 任务队列长度监控,防止内存泄漏。 + - 心跳超时阈值调优,平衡实时性与资源消耗。 ## 故障排查指南 - 常见问题定位 @@ -439,13 +589,16 @@ end - CORS:确认 app/main.py 中允许的源与方法。 - 数据库连接:检查 DATABASE_URL 与网络连通性。 - Playwright:确保已安装浏览器二进制;查看适配器初始化日志。 + - **新增** 智能体框架:检查 Redis 连接状态,验证 Agent 注册与心跳。 - 日志与监控 - 调度器与平台适配器均输出详细日志,定位失败原因。 - 前端统一错误处理:lib/api.ts 在请求失败时抛出错误,便于 UI 提示。 + - **新增** 智能体框架日志:监控任务状态变化和配置更新历史。 - 快速恢复 - 重启后端服务与前端构建;检查 .env 配置是否正确;核对迁移是否执行。 + - **新增** 智能体框架恢复:重启 Redis 服务,重新注册 Agent,检查任务队列。 -章节来源 +**章节来源** - [backend/app/main.py:45-47](file://backend/app/main.py#L45-L47) - [backend/app/main.py:30-36](file://backend/app/main.py#L30-L36) - [backend/app/config.py:7](file://backend/app/config.py#L7) @@ -453,7 +606,7 @@ end - [frontend/lib/api.ts:16-21](file://frontend/lib/api.ts#L16-L21) ## 结论 -GEO 平台提供了清晰的分层架构与可扩展点:路由层、服务层、数据层与工作器层相互解耦,配合配置中心与前端统一 API 封装,能够高效支撑业务扩展。通过平台适配器插件化、Schema/模型标准化、调度器与任务队列机制,团队可以快速接入新 AI 平台、扩展前端页面与数据模型,并在生产环境中保持稳定与可观测。 +GEO 平台提供了清晰的分层架构与可扩展点:路由层、服务层、数据层与工作器层相互解耦,配合配置中心与前端统一 API 封装,能够高效支撑业务扩展。**新增的智能体框架进一步增强了平台的扩展能力**:通过 Agent 注册中心、配置管理、任务调度和管道编排,团队可以快速接入新 AI 平台、扩展前端页面与数据模型,并在生产环境中保持稳定与可观测。通过平台适配器插件化、Schema/模型标准化、调度器与任务队列机制,以及智能体框架的动态扩展能力,团队可以构建更加灵活和强大的 AI 应用平台。 ## 附录 @@ -467,15 +620,24 @@ GEO 平台提供了清晰的分层架构与可扩展点:路由层、服务层 - 案例三:前端新增报表页面 - 步骤:新增页面与路由 → 引入图表组件 → 调用后端报表接口 → 权限控制与数据可视化。 - 建议:复用现有 UI 组件库,保持设计一致性。 +- **新增** 案例四:智能体系统集成 + - 步骤:实现 Agent 能力声明 → 注册到 AgentRegistry → 配置管理 → 任务分发 → 管道编排。 + - 建议:使用心跳机制监控 Agent 状态,实现自动故障转移。 +- **新增** 案例五:LLM 提供商扩展 + - 步骤:在配置中添加新提供商 → 实现工厂模式 → 更新默认配置 → 前端配置界面适配。 + - 建议:实现统一的 API 调用抽象,支持多提供商切换。 ### 部署与运行要点 - 使用 Docker Compose 启动后端与前端服务,确保端口映射与网络互通。 - 后端 Dockerfile 与 requirements.txt 已配置,注意镜像构建缓存与依赖锁定。 - 前端 Dockerfile 与 Next.js 版本已固定,构建产物由 Next.js 管理。 +- **新增** 智能体框架部署:确保 Redis 服务可用,配置正确的 REDIS_URL。 +- **新增** 环境配置:使用 .env.example 作为模板,配置所有必要的环境变量。 -章节来源 +**章节来源** - [docker-compose.yml](file://docker-compose.yml) - [backend/Dockerfile](file://backend/Dockerfile) - [frontend/Dockerfile](file://frontend/Dockerfile) - [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) -- [frontend/package.json:11-27](file://frontend/package.json#L11-L27) \ No newline at end of file +- [frontend/package.json:11-27](file://frontend/package.json#L11-L27) +- [.env.example:1-35](file://.env.example#L1-L35) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/数据库设计.md b/.qoder/repowiki/zh/content/数据库设计/数据库设计.md index 3456045..eff2fc2 100644 --- a/.qoder/repowiki/zh/content/数据库设计/数据库设计.md +++ b/.qoder/repowiki/zh/content/数据库设计/数据库设计.md @@ -8,11 +8,19 @@ - [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py) - [backend/app/models/query_task.py](file://backend/app/models/query_task.py) - [backend/app/models/subscription.py](file://backend/app/models/subscription.py) +- [backend/app/models/lifecycle.py](file://backend/app/models/lifecycle.py) +- [backend/app/models/analytics.py](file://backend/app/models/analytics.py) +- [backend/app/models/alert.py](file://backend/app/models/alert.py) +- [backend/app/models/knowledge.py](file://backend/app/models/knowledge.py) - [backend/app/models/__init__.py](file://backend/app/models/__init__.py) - [backend/alembic/env.py](file://backend/alembic/env.py) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py) - [backend/alembic.ini](file://backend/alembic.ini) - [backend/app/config.py](file://backend/app/config.py) - [docker-compose.yml](file://docker-compose.yml) @@ -23,15 +31,19 @@ - [backend/app/api/auth.py](file://backend/app/api/auth.py) - [backend/app/api/citations.py](file://backend/app/api/citations.py) - [backend/app/api/reports.py](file://backend/app/api/reports.py) +- [backend/app/api/lifecycle.py](file://backend/app/api/lifecycle.py) +- [backend/app/api/analytics.py](file://backend/app/api/analytics.py) +- [backend/app/api/alerts.py](file://backend/app/api/alerts.py) +- [backend/app/api/knowledge.py](file://backend/app/api/knowledge.py) ## 更新摘要 **变更内容** -- 新增用户管理相关字段的数据库迁移(email_verified、verification_code、reset_token等) -- 更新User模型以支持完整的用户认证和管理功能 -- 新增用户注册、登录、邮箱验证、密码重置等认证API -- 增强用户角色管理,支持管理员权限控制 -- 更新数据库迁移版本链,从初始版本到最新版本 +- 新增业务生命周期管理系统:组织、项目、阶段、代理、内容、规则、知识库等表 +- 新增分析监控系统:发布记录、内容指标、优化洞察等表 +- 新增告警系统:告警记录和告警设置表 +- 新增知识库系统:支持向量检索的完整知识管理架构 +- 更新数据库迁移版本链,包含11个版本的完整架构演进 ## 目录 1. [简介](#简介) @@ -55,11 +67,13 @@ - 性能优化、查询分析与缓存策略 - 备份、恢复与维护最佳实践 +**更新** 新增完整的业务生命周期、分析监控、告警系统、知识库等企业级功能架构,形成从用户管理到智能代理的完整数据体系。 + ## 项目结构 后端采用 FastAPI + SQLAlchemy Async + Alembic 迁移的典型分层架构: - 配置层:读取环境变量,提供数据库连接字符串 - 数据库引擎与会话:异步连接池与会话工厂 -- ORM 模型层:用户、查询、引用记录、任务、订阅 +- ORM 模型层:用户、查询、引用记录、任务、订阅、生命周期、分析监控、告警、知识库 - 迁移层:Alembic 初始化迁移脚本 - 服务层:业务查询封装,统一事务边界 - 容器编排:Docker Compose 启动 Postgres 与 Redis @@ -68,24 +82,37 @@ graph TB subgraph "应用层" AuthAPI["API: 认证
backend/app/api/auth.py"] -API["API: 引用
backend/app/api/citations.py"] -Reports["API: 报告
backend/app/api/reports.py"] +LifeCycleAPI["API: 生命周期
backend/app/api/lifecycle.py"] +AnalyticsAPI["API: 分析监控
backend/app/api/analytics.py"] +AlertsAPI["API: 告警系统
backend/app/api/alerts.py"] +KnowledgeAPI["API: 知识库
backend/app/api/knowledge.py"] +CitationsAPI["API: 引用
backend/app/api/citations.py"] +ReportsAPI["API: 报告
backend/app/api/reports.py"] end subgraph "服务层" SvcAuth["服务: 认证
backend/app/services/auth.py"] -SvcQ["服务: 查询
backend/app/services/query.py"] -SvcC["服务: 引用
backend/app/services/citation.py"] +SvcLifeCycle["服务: 生命周期
backend/app/services/lifecycle.py"] +SvcAnalytics["服务: 分析监控
backend/app/services/analytics.py"] +SvcAlerts["服务: 告警系统
backend/app/services/alert_engine.py"] +SvcKnowledge["服务: 知识库
backend/app/services/knowledge/"] +SvcCitations["服务: 引用
backend/app/services/citation.py"] +SvcReports["服务: 报告
backend/app/services/reports.py"] end subgraph "ORM 层" MUser["模型: 用户
backend/app/models/user.py"] +MLifeCycle["模型: 生命周期
backend/app/models/lifecycle.py"] +MAnalytics["模型: 分析监控
backend/app/models/analytics.py"] +MAlerts["模型: 告警系统
backend/app/models/alert.py"] +MKnowledge["模型: 知识库
backend/app/models/knowledge.py"] MQuery["模型: 查询
backend/app/models/query.py"] -MCit["模型: 引用记录
backend/app/models/citation_record.py"] +MCitation["模型: 引用记录
backend/app/models/citation_record.py"] MTask["模型: 查询任务
backend/app/models/query_task.py"] -MSub["模型: 订阅
backend/app/models/subscription.py"] +MSubscription["模型: 订阅
backend/app/models/subscription.py"] end subgraph "基础设施" DB["PostgreSQL 数据库"] RD["Redis 缓存"] +Vector["向量数据库"] end Cfg["配置: DATABASE_URL
backend/app/config.py"] Eng["引擎与会话
backend/app/database.py"] @@ -93,33 +120,46 @@ Alembic["迁移: Alembic
backend/alembic/*"] Cfg --> Eng Eng --> DB AuthAPI --> SvcAuth -API --> SvcC -Reports --> SvcC +LifeCycleAPI --> SvcLifeCycle +AnalyticsAPI --> SvcAnalytics +AlertsAPI --> SvcAlerts +KnowledgeAPI --> SvcKnowledge +CitationsAPI --> SvcCitations +ReportsAPI --> SvcReports SvcAuth --> Eng -SvcQ --> Eng -SvcC --> Eng +SvcLifeCycle --> Eng +SvcAnalytics --> Eng +SvcAlerts --> Eng +SvcKnowledge --> Eng +SvcCitations --> Eng +SvcReports --> Eng MUser --> Eng +MLifeCycle --> Eng +MAnalytics --> Eng +MAlerts --> Eng +MKnowledge --> Eng MQuery --> Eng -MCit --> Eng +MCitation --> Eng MTask --> Eng -MSub --> Eng +MSubscription --> Eng Alembic --> DB SvcAuth --> RD -SvcC --> RD +SvcCitations --> RD +SvcKnowledge --> Vector ``` -图表来源 +**图表来源** - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/models/user.py:1-48](file://backend/app/models/user.py#L1-L48) -- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) -- [backend/app/models/citation_record.py:1-44](file://backend/app/models/citation_record.py#L1-L44) -- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39) -- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37) +- [backend/app/models/lifecycle.py:1-92](file://backend/app/models/lifecycle.py#L1-L92) +- [backend/app/models/analytics.py:1-64](file://backend/app/models/analytics.py#L1-L64) +- [backend/app/models/alert.py:1-75](file://backend/app/models/alert.py#L1-L75) +- [backend/app/models/knowledge.py:1-213](file://backend/app/models/knowledge.py#L1-L213) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) -章节来源 +**章节来源** - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) @@ -136,18 +176,30 @@ SvcC --> RD - Alembic 环境集成 SQLAlchemy Base 元数据,支持离线/在线迁移。 - 初始迁移脚本定义了用户、查询、引用记录、查询任务、订阅五张表及必要索引。 - 新增迁移版本支持confidence和match_type字段,增强报告功能。 + - **新增** 生命周期迁移(d4f6g8h0ab23):新增组织、项目、阶段、代理、内容、规则、知识库等完整业务架构。 + - **新增** 分析监控迁移(f6g8h0i2de56):新增发布记录、内容指标、优化洞察等分析监控表。 + - **新增** 告警系统迁移(e5f7a9b1cd34):新增告警记录和告警设置表。 + - **新增** 知识库迁移(e5f7g9h1cd45):新增支持向量检索的知识库完整架构。 - **新增** 最新迁移版本添加用户管理相关字段,支持完整的用户认证和管理功能。 - 服务层封装 - 查询与引用统计、导出等业务逻辑封装在服务层,统一执行 SQL 并返回结果。 - 对外暴露清晰的查询接口,内部进行权限校验与计数限制。 - **新增** 认证服务封装用户注册、登录、验证等功能。 + - **新增** 生命周期服务管理项目全生命周期。 + - **新增** 分析监控服务处理内容发布和指标收集。 + - **新增** 告警引擎服务处理实时告警。 + - **新增** 知识库服务处理向量检索和RAG。 -章节来源 +**章节来源** - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:1-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L1-L128) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py:1-37](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#L1-L37) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py:1-41](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#L1-L41) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py:1-398](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#L1-L398) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py:1-125](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#L1-L125) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py:1-86](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#L1-L86) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py:1-224](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#L1-L224) - [backend/app/services/query.py:1-130](file://backend/app/services/query.py#L1-L130) - [backend/app/services/citation.py:1-429](file://backend/app/services/citation.py#L1-L429) - [backend/app/services/auth.py:1-175](file://backend/app/services/auth.py#L1-L175) @@ -159,31 +211,48 @@ SvcC --> RD sequenceDiagram participant Client as "客户端" participant AuthAPI as "认证API" -participant API as "FastAPI 应用" +participant LifeCycleAPI as "生命周期API" +participant AnalyticsAPI as "分析监控API" +participant AlertsAPI as "告警API" +participant KnowledgeAPI as "知识库API" participant SvcAuth as "认证服务" -participant SvcC as "引用服务" -participant Reports as "报告服务" +participant SvcLifeCycle as "生命周期服务" +participant SvcAnalytics as "分析监控服务" +participant SvcAlerts as "告警引擎服务" +participant SvcKnowledge as "知识库服务" participant DB as "PostgreSQL" participant Alembic as "迁移工具" Client->>AuthAPI : 请求 /auth/register 登录 AuthAPI->>SvcAuth : 调用认证服务 SvcAuth->>DB : 执行用户注册/验证 -Client->>API : 请求 /citations 或 /reports -API->>SvcC : 调用引用服务 -SvcC->>DB : 执行查询/统计/插入 -API->>Reports : 调用报告服务 -Reports->>DB : 执行导出查询 -DB-->>Reports : 返回统计数据 -DB-->>SvcC : 返回引用记录 +Client->>LifeCycleAPI : 请求生命周期管理 +LifeCycleAPI->>SvcLifeCycle : 调用生命周期服务 +SvcLifeCycle->>DB : 执行项目/阶段管理 +Client->>AnalyticsAPI : 请求分析监控 +AnalyticsAPI->>SvcAnalytics : 调用分析监控服务 +SvcAnalytics->>DB : 执行发布记录/指标收集 +Client->>AlertsAPI : 请求告警管理 +AlertsAPI->>SvcAlerts : 调用告警引擎服务 +SvcAlerts->>DB : 执行告警记录/设置 +Client->>KnowledgeAPI : 请求知识检索 +KnowledgeAPI->>SvcKnowledge : 调用知识库服务 +SvcKnowledge->>DB : 执行向量检索 +SvcKnowledge->>Vector : 执行相似度搜索 +DB-->>SvcKnowledge : 返回检索结果 +DB-->>SvcAlerts : 返回告警数据 +DB-->>SvcAnalytics : 返回监控数据 +DB-->>SvcLifeCycle : 返回生命周期数据 DB-->>SvcAuth : 返回用户信息 -Reports-->>API : 返回CSV内容 -SvcC-->>API : 返回查询列表/详情 +SvcKnowledge-->>KnowledgeAPI : 返回检索结果 +SvcAlerts-->>AlertsAPI : 返回告警数据 +SvcAnalytics-->>AnalyticsAPI : 返回监控数据 +SvcLifeCycle-->>LifeCycleAPI : 返回生命周期数据 SvcAuth-->>AuthAPI : 返回认证结果 AuthAPI-->>Client : 响应认证数据 Note over Alembic,DB : 首次启动或升级时执行迁移 ``` -图表来源 +**图表来源** - [backend/app/services/citation.py:1-429](file://backend/app/services/citation.py#L1-L429) - [backend/app/services/auth.py:1-175](file://backend/app/services/auth.py#L1-L175) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) @@ -191,13 +260,31 @@ Note over Alembic,DB : 首次启动或升级时执行迁移 ## 详细组件分析 ### 实体关系映射(ER) -- 用户(users):主键 id,唯一邮箱,计划与配额字段,活跃状态,**新增**邮箱验证状态、验证码及其过期时间、重置令牌及其过期时间、头像URL、管理员权限,时间戳。 -- 查询(queries):外键 user_id,关键词、目标品牌、别名列表、平台列表、频率、状态、下次查询时间,时间戳。 -- 引用记录(citation_records):外键 query_id,平台、是否引用、引用位置、引用文本、竞争品牌列表、原始响应、匹配置信度、匹配类型、查询时间。 -- 查询任务(query_tasks):外键 query_id,平台、状态、错误信息、调度/开始/完成时间。 -- 订阅(subscriptions):外键 user_id,计划、状态、起止日期、金额、支付方式与流水号,时间戳。 +- 用户(users):主键 id,唯一邮箱,计划与配额字段,活跃状态,**新增**组织关联、角色字段,邮箱验证状态、验证码及其过期时间、重置令牌及其过期时间、头像URL、管理员权限,时间戳。 +- 组织(organizations):主键 id,名称、slug唯一约束、描述、logo、计划、最大成员数,时间戳。 +- 生命周期项目(lifecycle_projects):主键 id,组织外键,品牌名称、别名列表、当前阶段、状态、创建者外键,时间戳。 +- 项目阶段(project_stages):主键 id,项目外键,阶段编号、状态、开始/完成时间、备注、指标,唯一索引(project_id, stage_number)。 +- 代理注册表(agent_registry):主键 id,名称唯一约束、显示名称、代理类型、描述、版本、端点、状态、能力、心跳时间,索引(name, agent_type, status)。 +- 代理配置(agent_configs):主键 id,代理外键,配置键唯一约束,配置值、描述、更新时间、更新者外键。 +- 代理任务(agent_tasks):主键 id,代理外键,任务类型、状态、优先级、输入输出数据、错误信息、创建者、组织、项目外键,索引(agent_id, status, organization_id, project_id, created_by, task_type)。 +- 代理任务日志(agent_task_logs):主键 id,任务外键,代理外键,日志级别、消息、元数据,索引(task_id, agent_id, created_at)。 +- 内容(contents):主键 id,组织外键,项目外键,标题、类型、正文、状态、目标平台、关键词、元数据、创建者外键,索引(organization_id, project_id, status, content_type, created_by)。 +- 内容版本(content_versions):主键 id,内容外键,版本号、标题、正文、变更摘要、创建者外键,唯一索引(content_id, version_number)。 +- 内容审核(content_reviews):主键 id,内容外键,审核者外键,状态、评论,索引(content_id, reviewer_id)。 +- 平台规则(platform_rules):主键 id,平台、规则类别、规则名称、描述、检查标准、严重程度、激活状态,索引(platform, rule_category, is_active)。 +- 品牌知识(brand_knowledge):主键 id,组织外键,类别、标题、内容、元数据、激活状态、创建者外键,索引(organization_id, category, is_active)。 +- 关键词(keywords):主键 id,组织外键,项目外键,关键词、类别、优先级、搜索量、竞争等级、状态,索引(organization_id, project_id, category, status, keyword)。 +- 发布记录(publish_records):主键 id,组织外键,内容标题、内容ID、平台、发布URL、状态、发布时间,索引(organization_id, platform, status, created_at)。 +- 内容指标(content_metrics):主键 id,发布记录外键,记录时间,互动指标、AI引用次数、搜索曝光点击、阅读指标,索引(publish_record_id, recorded_at)。 +- 优化洞察(optimization_insights):主键 id,组织外键,内容ID、洞察类型、标题、描述、建议、严重程度、是否已应用,索引(organization_id, insight_type, created_at)。 +- 告警(alerts):主键 id,品牌外键,用户外键,告警类型、严重程度、标题、消息、数据、是否已读,索引(user_id, brand_id, alert_type, is_read, created_at)。 +- 告警设置(alert_settings):主键 id,品牌外键,用户外键,告警类型、是否启用、阈值,索引(brand_id, user_id, brand_id, alert_type)。 +- 知识库(knowledge_bases):主键 id,组织外键,名称、类型、描述、文档数量、状态、创建者外键,索引(organization_id, type, status)。 +- 知识文档(knowledge_documents):主键 id,知识库外键,标题、来源类型、URL、内容、内容哈希、分块数量、状态、错误信息、元数据,索引(knowledge_base_id, status, content_hash)。 +- 知识分块(knowledge_chunks):主键 id,文档外键,内容、嵌入向量、分块索引、token数量、元数据,索引(document_id, document_id, chunk_index)。 +- 知识检索日志(knowledge_search_logs):主键 id,组织外键,用户外键,查询、知识库ID列表、结果数量、延迟毫秒,索引(organization_id, user_id, created_at)。 -**更新** 用户表新增完整的用户管理字段,支持邮箱验证、密码重置、头像管理和管理员权限控制。 +**更新** 新增完整的业务生命周期、分析监控、告警系统、知识库等企业级功能架构,形成从用户管理到智能代理的完整数据体系。 ```mermaid erDiagram @@ -209,6 +296,8 @@ string name string plan integer max_queries boolean is_active +uuid organization_id FK +string role boolean email_verified string verification_code timestamptz verification_code_expires @@ -219,74 +308,308 @@ boolean is_admin timestamptz created_at timestamptz updated_at } -QUERIES { +ORGANIZATIONS { uuid id PK -uuid user_id FK -string keyword -string target_brand -jsonb brand_aliases -jsonb platforms -string frequency -string status -timestamptz last_queried_at -timestamptz next_query_at +string name +string slug UK +text description +string logo_url +string plan +integer max_members timestamptz created_at timestamptz updated_at } -CITATION_RECORDS { +LIFECYCLE_PROJECTS { uuid id PK -uuid query_id FK -string platform -boolean cited -integer citation_position -text citation_text -jsonb competitor_brands -text raw_response -float confidence -string match_type -timestamptz queried_at -} -QUERY_TASKS { -uuid id PK -uuid query_id FK -string platform +uuid organization_id FK +string brand_name +jsonb brand_aliases +integer current_stage string status +uuid created_by FK +timestamptz created_at +timestamptz updated_at +} +PROJECT_STAGES { +uuid id PK +uuid project_id FK +integer stage_number +string status +timestamptz started_at +timestamptz completed_at +text notes +jsonb metrics +} +AGENT_REGISTRY { +uuid id PK +string name UK +string display_name +string agent_type +text description +string version +string endpoint +string status +jsonb capabilities +timestamptz last_heartbeat +timestamptz created_at +timestamptz updated_at +} +AGENT_CONFIGS { +uuid id PK +uuid agent_id FK +string config_key +jsonb config_value +string description +timestamptz updated_at +uuid updated_by FK +} +AGENT_TASKS { +uuid id PK +uuid agent_id FK +string task_type +string status +integer priority +jsonb input_data +jsonb output_data text error_message +uuid created_by FK +uuid organization_id FK +uuid project_id FK timestamptz scheduled_at timestamptz started_at timestamptz completed_at -} -SUBSCRIPTIONS { -uuid id PK -uuid user_id FK -string plan -string status -date start_date -date end_date -numeric amount -string payment_method -string payment_id timestamptz created_at } -USERS ||--o{ QUERIES : "拥有" -QUERIES ||--o{ CITATION_RECORDS : "产生" -QUERIES ||--o{ QUERY_TASKS : "触发" -USERS ||--o{ SUBSCRIPTIONS : "订阅" +AGENT_TASK_LOGS { +uuid id PK +uuid task_id FK +uuid agent_id FK +string log_level +text message +jsonb metadata +timestamptz created_at +} +CONTENTS { +uuid id PK +uuid organization_id FK +uuid project_id FK +string title +string content_type +text body +string status +jsonb target_platforms +jsonb keywords +jsonb metadata +uuid created_by FK +integer current_version +timestamptz created_at +timestamptz updated_at +} +CONTENT_VERSIONS { +uuid id PK +uuid content_id FK +integer version_number +string title +text body +string change_summary +uuid created_by FK +timestamptz created_at +} +CONTENT_REVIEWS { +uuid id PK +uuid content_id FK +uuid reviewer_id FK +string status +text comments +timestamptz created_at +} +PLATFORM_RULES { +uuid id PK +string platform +string rule_category +string rule_name +text description +jsonb check_criteria +string severity +boolean is_active +timestamptz updated_at +} +BRAND_KNOWLEDGE { +uuid id PK +uuid organization_id FK +string category +string title +text content +jsonb metadata +boolean is_active +uuid created_by FK +timestamptz created_at +timestamptz updated_at +} +KEYWORDS { +uuid id PK +uuid organization_id FK +uuid project_id FK +string keyword +string category +integer priority +integer search_volume +string competition_level +string status +timestamptz created_at +} +PUBLISH_RECORDS { +string id PK +string organization_id FK +string content_title +string content_id +string platform +string published_url +string status +timestamptz published_at +timestamptz created_at +} +CONTENT_METRICS { +string id PK +string publish_record_id FK +timestamptz recorded_at +integer views +integer likes +integer comments +integer shares +integer bookmarks +integer ai_citation_count +integer search_impressions +integer search_clicks +float avg_read_duration +float read_completion_rate +} +OPTIMIZATION_INSIGHTS { +string id PK +string organization_id FK +string content_id +string insight_type +string title +text description +text recommendation +string severity +boolean applied +timestamptz created_at +} +ALERTS { +uuid id PK +uuid brand_id FK +uuid user_id FK +string alert_type +string severity +string title +text message +jsonb data +boolean is_read +timestamptz created_at +} +ALERT_SETTINGS { +uuid id PK +uuid brand_id FK +uuid user_id FK +string alert_type +boolean enabled +float threshold +timestamptz created_at +timestamptz updated_at +} +KNOWLEDGE_BASES { +uuid id PK +uuid organization_id FK +string name +string type +text description +integer document_count +string status +uuid created_by FK +timestamptz created_at +timestamptz updated_at +} +KNOWLEDGE_DOCUMENTS { +uuid id PK +uuid knowledge_base_id FK +string title +string source_type +string source_url +text content +string content_hash +integer chunk_count +string status +text error_message +jsonb metadata +timestamptz created_at +timestamptz updated_at +} +KNOWLEDGE_CHUNKS { +uuid id PK +uuid document_id FK +text content +vector embedding +integer chunk_index +integer token_count +jsonb metadata +timestamptz created_at +} +KNOWLEDGE_SEARCH_LOGS { +uuid id PK +uuid organization_id FK +uuid user_id FK +text query +jsonb knowledge_base_ids +integer results_count +integer latency_ms +timestamptz created_at +} +USERS ||--o{ ORGANIZATIONS : "属于" +ORGANIZATIONS ||--o{ LIFECYCLE_PROJECTS : "拥有" +LIFECYCLE_PROJECTS ||--o{ PROJECT_STAGES : "包含" +USERS ||--o{ LIFECYCLE_PROJECTS : "创建" +USERS ||--o{ AGENT_TASKS : "创建" +ORGANIZATIONS ||--o{ AGENT_TASKS : "拥有" +LIFECYCLE_PROJECTS ||--o{ AGENT_TASKS : "关联" +AGENT_REGISTRY ||--o{ AGENT_TASKS : "注册" +AGENT_TASKS ||--o{ AGENT_TASK_LOGS : "产生" +ORGANIZATIONS ||--o{ CONTENTS : "拥有" +LIFECYCLE_PROJECTS ||--o{ CONTENTS : "关联" +USERS ||--o{ CONTENTS : "创建" +CONTENTS ||--o{ CONTENT_VERSIONS : "版本化" +CONTENTS ||--o{ CONTENT_REVIEWS : "审核" +ORGANIZATIONS ||--o{ PLATFORM_RULES : "拥有" +ORGANIZATIONS ||--o{ BRAND_KNOWLEDGE : "拥有" +ORGANIZATIONS ||--o{ KEYWORDS : "拥有" +LIFECYCLE_PROJECTS ||--o{ KEYWORDS : "关联" +ORGANIZATIONS ||--o{ PUBLISH_RECORDS : "拥有" +PUBLISH_RECORDS ||--o{ CONTENT_METRICS : "产生" +ORGANIZATIONS ||--o{ OPTIMIZATION_INSIGHTS : "拥有" +USERS ||--o{ ALERTS : "拥有" +BRANDS ||--o{ ALERTS : "关联" +USERS ||--o{ ALERT_SETTINGS : "拥有" +BRANDS ||--o{ ALERT_SETTINGS : "关联" +ORGANIZATIONS ||--o{ KNOWLEDGE_BASES : "拥有" +KNOWLEDGE_BASES ||--o{ KNOWLEDGE_DOCUMENTS : "包含" +KNOWLEDGE_DOCUMENTS ||--o{ KNOWLEDGE_CHUNKS : "分块" +ORGANIZATIONS ||--o{ KNOWLEDGE_SEARCH_LOGS : "拥有" +USERS ||--o{ KNOWLEDGE_SEARCH_LOGS : "使用" ``` -图表来源 +**图表来源** - [backend/app/models/user.py:11-48](file://backend/app/models/user.py#L11-L48) -- [backend/app/models/query.py:11-48](file://backend/app/models/query.py#L11-L48) -- [backend/app/models/citation_record.py:11-44](file://backend/app/models/citation_record.py#L11-L44) -- [backend/app/models/query_task.py:11-34](file://backend/app/models/query_task.py#L11-L34) -- [backend/app/models/subscription.py:11-36](file://backend/app/models/subscription.py#L11-L36) +- [backend/app/models/lifecycle.py:12-92](file://backend/app/models/lifecycle.py#L12-L92) +- [backend/app/models/analytics.py:9-64](file://backend/app/models/analytics.py#L9-L64) +- [backend/app/models/alert.py:24-75](file://backend/app/models/alert.py#L24-L75) +- [backend/app/models/knowledge.py:22-213](file://backend/app/models/knowledge.py#L22-L213) -章节来源 +**章节来源** - [backend/app/models/user.py:1-48](file://backend/app/models/user.py#L1-L48) -- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) -- [backend/app/models/citation_record.py:1-44](file://backend/app/models/citation_record.py#L1-L44) -- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39) -- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37) +- [backend/app/models/lifecycle.py:1-92](file://backend/app/models/lifecycle.py#L1-L92) +- [backend/app/models/analytics.py:1-64](file://backend/app/models/analytics.py#L1-L64) +- [backend/app/models/alert.py:1-75](file://backend/app/models/alert.py#L1-L75) +- [backend/app/models/knowledge.py:1-213](file://backend/app/models/knowledge.py#L1-L213) ### 索引策略 - 查询表(queries) @@ -301,25 +624,107 @@ USERS ||--o{ SUBSCRIPTIONS : "订阅" - **新增** idx_citation_records_match_type:按匹配类型过滤(建议) - **新增** 用户表(users) - idx_users_email:按邮箱快速查找 + - idx_users_organization_id:按组织关联 - idx_users_verification_code:按验证码快速验证 - idx_users_reset_token:按重置令牌快速验证 +- **新增** 组织表(organizations) + - idx_organizations_slug:按slug快速查找 +- **新增** 生命周期项目表(lifecycle_projects) + - idx_lifecycle_projects_organization_id:按组织过滤 + - idx_lifecycle_projects_status:按状态过滤 + - idx_lifecycle_projects_brand_name:按品牌名称过滤 +- **新增** 项目阶段表(project_stages) + - idx_project_stages_project_id:按项目过滤 + - idx_project_stages_status:按状态过滤 + - idx_project_stages_project_stage:按项目和阶段唯一约束 +- **新增** 代理注册表(agent_registry) + - idx_agent_registry_name:按名称快速查找 + - idx_agent_registry_agent_type:按代理类型过滤 + - idx_agent_registry_status:按状态过滤 +- **新增** 代理任务表(agent_tasks) + - idx_agent_tasks_agent_id:按代理过滤 + - idx_agent_tasks_status:按状态过滤 + - idx_agent_tasks_organization_id:按组织过滤 + - idx_agent_tasks_project_id:按项目过滤 + - idx_agent_tasks_created_by:按创建者过滤 + - idx_agent_tasks_task_type:按任务类型过滤 +- **新增** 内容表(contents) + - idx_contents_organization_id:按组织过滤 + - idx_contents_project_id:按项目过滤 + - idx_contents_status:按状态过滤 + - idx_contents_content_type:按类型过滤 + - idx_contents_created_by:按创建者过滤 +- **新增** 知识库表(knowledge_bases) + - idx_knowledge_bases_organization_id:按组织过滤 + - idx_knowledge_bases_type:按类型过滤 + - idx_knowledge_bases_status:按状态过滤 +- **新增** 知识文档表(knowledge_documents) + - idx_knowledge_documents_knowledge_base_id:按知识库过滤 + - idx_knowledge_documents_status:按状态过滤 + - idx_knowledge_documents_content_hash:按内容哈希过滤 +- **新增** 知识分块表(knowledge_chunks) + - idx_knowledge_chunks_document_id:按文档过滤 + - idx_knowledge_chunks_chunk_index:按分块索引过滤 + - **新增** 向量索引:ix_knowledge_chunks_embedding(HNSW近似最近邻搜索) +- **新增** 分析监控表 + - idx_publish_records_organization_id:按组织过滤 + - idx_publish_records_platform:按平台过滤 + - idx_publish_records_status:按状态过滤 + - idx_publish_records_created_at:按创建时间过滤 + - idx_content_metrics_publish_record_id:按发布记录过滤 + - idx_content_metrics_recorded_at:按记录时间过滤 + - idx_optimization_insights_organization_id:按组织过滤 + - idx_optimization_insights_insight_type:按洞察类型过滤 + - idx_optimization_insights_created_at:按创建时间过滤 +- **新增** 告警系统表 + - idx_alerts_user_id:按用户过滤 + - idx_alerts_brand_id:按品牌过滤 + - idx_alerts_alert_type:按告警类型过滤 + - idx_alerts_is_read:按是否已读过滤 + - idx_alerts_created_at:按创建时间过滤 + - idx_alerts_user_read:按用户和已读状态组合过滤 + - idx_alert_settings_brand_id:按品牌过滤 + - idx_alert_settings_user_id:按用户过滤 + - idx_alert_settings_brand_type:按品牌和类型组合唯一约束 -**更新** 新增针对用户管理字段的索引建议,支持高效的用户认证和验证操作。 +**更新** 新增针对所有新增表的索引策略,特别是知识库的向量索引和告警系统的复合索引。 这些索引覆盖了常见查询路径与统计场景,有助于提升分页、过滤、排序与聚合的性能。 -章节来源 +**章节来源** - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:57-94](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L57-L94) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py:21-37](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#L21-L37) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py:21-41](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#L21-L41) -- [backend/app/models/query.py:50-54](file://backend/app/models/query.py#L50-L54) -- [backend/app/models/citation_record.py:37-44](file://backend/app/models/citation_record.py#L37-L44) -- [backend/app/models/query_task.py:36-38](file://backend/app/models/query_task.py#L36-L38) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py:24-398](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#L24-L398) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py:24-125](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#L24-L125) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py:24-86](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#L24-L86) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py:30-224](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#L30-L224) ### SQLAlchemy ORM 模型实现 - 字段类型与默认值 - UUID 主键与外键,JSONB 存储数组/字典,布尔、整数、文本、数值、时间戳等。 - 默认值通过 server_default/onupdate 设置,减少应用层重复逻辑。 + - **新增** 组织表:slug唯一约束,max_members默认5,plan默认'free'。 + - **新增** 生命周期项目表:current_stage默认1,status默认'active'。 + - **新增** 项目阶段表:status默认'pending',stage_number非空。 + - **新增** 代理注册表:name唯一约束,status默认'offline'。 + - **新增** 代理配置表:config_key唯一约束,updated_at自动更新。 + - **新增** 代理任务表:多个索引字段,status默认'pending',priority默认0。 + - **新增** 内容表:status默认'draft',current_version默认1。 + - **新增** 内容版本表:version_number非空,unique约束。 + - **新增** 内容审核表:status非空。 + - **新增** 平台规则表:severity非空,is_active默认true。 + - **新增** 品牌知识表:is_active默认true。 + - **新增** 关键词表:priority默认0,status默认'active'。 + - **新增** 发布记录表:status默认'draft'。 + - **新增** 内容指标表:多个默认值,avg_read_duration默认0.0。 + - **新增** 优化洞察表:severity默认'info',applied默认false。 + - **新增** 告警表:is_read默认false。 + - **新增** 告警设置表:enabled默认true,threshold可为空。 + - **新增** 知识库表:document_count默认0,status默认'active'。 + - **新增** 知识文档表:chunk_count默认0,status默认'processing'。 + - **新增** 知识分块表:token_count默认0。 + - **新增** 知识检索日志表:results_count默认0,latency_ms默认0。 - **新增** email_verified字段(Boolean类型,默认False)用于邮箱验证状态。 - **新增** verification_code字段(String类型,长度6,nullable=True)用于存储6位验证码。 - **新增** verification_code_expires字段(DateTime类型,nullable=True)用于验证码过期时间。 @@ -330,13 +735,40 @@ USERS ||--o{ SUBSCRIPTIONS : "订阅" - **新增** confidence字段(Float类型,nullable=True)用于存储匹配的可信度评分。 - **新增** match_type字段(String类型,长度20,nullable=True)用于标识匹配类型。 - 关系配置 - - 用户与查询、订阅为一对多;查询与引用记录、任务为一对多。 - - 级联删除与孤儿对象清理(delete-orphan),避免悬挂数据。 + - 用户与组织:多对一,支持NULL值(用户未加入组织)。 + - 组织与生命周期项目:一对多,级联删除。 + - 项目与阶段:一对多,级联删除与孤儿对象清理。 + - 代理注册与配置:一对多,级联删除。 + - 代理注册与任务:一对多,级联删除。 + - 代理任务与日志:一对多,级联删除。 + - 组织与内容:一对多,级联删除。 + - 内容与版本:一对多,级联删除与唯一约束。 + - 内容与审核:一对多,级联删除。 + - 组织与平台规则:一对多,级联删除。 + - 组织与品牌知识:一对多,级联删除。 + - 组织与关键词:一对多,级联删除。 + - 项目与关键词:一对多,级联删除。 + - 知识库与文档:一对多,级联删除。 + - 文档与分块:一对多,级联删除。 + - 组织与发布记录:一对多,级联删除。 + - 发布记录与指标:一对多,级联删除。 + - 组织与优化洞察:一对多,级联删除。 + - 用户与告警:一对多,级联删除。 + - 品牌与告警:一对多,级联删除。 + - 用户与告警设置:一对多,级联删除。 + - 品牌与告警设置:一对多,级联删除。 + - 组织与知识库:一对多,级联删除。 + - 组织与知识检索日志:一对多,级联删除。 + - 用户与知识检索日志:一对多,级联删除。 - 查询封装 - 服务层使用 select + func + join 封装复杂查询,统一处理分页与计数。 - 权限校验:仅允许访问当前用户的资源,防止越权。 + - **新增** 生命周期服务:管理项目全生命周期,支持阶段转换和状态管理。 + - **新增** 分析监控服务:处理内容发布流程和指标收集。 + - **新增** 告警引擎服务:实时处理告警规则和通知。 + - **新增** 知识库服务:处理向量检索和RAG应用。 -**更新** User模型新增完整的用户管理字段,支持邮箱验证、密码重置、头像管理和管理员权限控制。 +**更新** 新增完整的生命周期、分析监控、告警系统、知识库等ORM模型实现,支持复杂的业务关系和查询需求。 ```mermaid classDiagram @@ -348,6 +780,8 @@ class User { +plan : string +max_queries : int +is_active : bool ++organization_id : uuid ++role : string +email_verified : bool +verification_code : string +verification_code_expires : datetime @@ -357,83 +791,360 @@ class User { +is_admin : bool +created_at : datetime +updated_at : datetime ++organization +queries +subscriptions ++lifecycle_projects ++agent_tasks ++contents ++knowledge_bases } -class Query { +class Organization { +id : uuid -+user_id : uuid -+keyword : string -+target_brand : string -+brand_aliases : list -+platforms : list -+frequency : string -+status : string -+last_queried_at : datetime -+next_query_at : datetime ++name : string ++slug : string ++description : string ++logo_url : string ++plan : string ++max_members : int +created_at : datetime +updated_at : datetime -+user -+citation_records -+query_tasks ++users ++lifecycle_projects ++agent_tasks ++contents ++platform_rules ++brand_knowledge ++keywords ++knowledge_bases ++publish_records ++optimization_insights ++knowledge_search_logs } -class CitationRecord { +class LifecycleProject { +id : uuid -+query_id : uuid -+platform : string -+cited : bool -+citation_position : int -+citation_text : text -+competitor_brands : list -+raw_response : text -+confidence : float -+match_type : string -+queried_at : datetime -+query -} -class QueryTask { -+id : uuid -+query_id : uuid -+platform : string ++organization_id : uuid ++brand_name : string ++brand_aliases : list ++current_stage : int +status : string -+error_message : text ++created_by : uuid ++created_at : datetime ++updated_at : datetime ++organization ++stages ++creator ++agent_tasks ++contents ++keywords +} +class ProjectStage { ++id : uuid ++project_id : uuid ++stage_number : int ++status : string ++started_at : datetime ++completed_at : datetime ++notes : string ++metrics : dict ++project +} +class AgentRegistry { ++id : uuid ++name : string ++display_name : string ++agent_type : string ++description : string ++version : string ++endpoint : string ++status : string ++capabilities : dict ++last_heartbeat : datetime ++created_at : datetime ++updated_at : datetime ++configs ++tasks +} +class AgentConfig { ++id : uuid ++agent_id : uuid ++config_key : string ++config_value : dict ++description : string ++updated_at : datetime ++updated_by : uuid ++agent +} +class AgentTask { ++id : uuid ++agent_id : uuid ++task_type : string ++status : string ++priority : int ++input_data : dict ++output_data : dict ++error_message : string ++created_by : uuid ++organization_id : uuid ++project_id : uuid +scheduled_at : datetime +started_at : datetime +completed_at : datetime -+query -} -class Subscription { -+id : uuid -+user_id : uuid -+plan : string -+status : string -+start_date : date -+end_date : date -+amount : float -+payment_method : string -+payment_id : string +created_at : datetime ++agent ++logs +} +class AgentTaskLog { ++id : uuid ++task_id : uuid ++agent_id : uuid ++log_level : string ++message : string ++metadata : dict ++created_at : datetime ++task ++agent +} +class Content { ++id : uuid ++organization_id : uuid ++project_id : uuid ++title : string ++content_type : string ++body : string ++status : string ++target_platforms : list ++keywords : list ++metadata : dict ++created_by : uuid ++current_version : int ++created_at : datetime ++updated_at : datetime ++versions ++reviews ++metrics +} +class ContentVersion { ++id : uuid ++content_id : uuid ++version_number : int ++title : string ++body : string ++change_summary : string ++created_by : uuid ++created_at : datetime ++content +} +class ContentReview { ++id : uuid ++content_id : uuid ++reviewer_id : uuid ++status : string ++comments : string ++created_at : datetime ++content ++reviewer +} +class PlatformRule { ++id : uuid ++platform : string ++rule_category : string ++rule_name : string ++description : string ++check_criteria : dict ++severity : string ++is_active : bool ++updated_at : datetime +} +class BrandKnowledge { ++id : uuid ++organization_id : uuid ++category : string ++title : string ++content : string ++metadata : dict ++is_active : bool ++created_by : uuid ++created_at : datetime ++updated_at : datetime ++organization ++creator +} +class Keyword { ++id : uuid ++organization_id : uuid ++project_id : uuid ++keyword : string ++category : string ++priority : int ++search_volume : int ++competition_level : string ++status : string ++created_at : datetime ++organization ++project +} +class PublishRecord { ++id : string ++organization_id : string ++content_title : string ++content_id : string ++platform : string ++published_url : string ++status : string ++published_at : datetime ++created_at : datetime ++metrics +} +class ContentMetrics { ++id : string ++publish_record_id : string ++recorded_at : datetime ++views : int ++likes : int ++comments : int ++shares : int ++bookmarks : int ++ai_citation_count : int ++search_impressions : int ++search_clicks : int ++avg_read_duration : float ++read_completion_rate : float ++publish_record +} +class OptimizationInsight { ++id : string ++organization_id : string ++content_id : string ++insight_type : string ++title : string ++description : string ++recommendation : string ++severity : string ++applied : bool ++created_at : datetime ++organization +} +class Alert { ++id : uuid ++brand_id : uuid ++user_id : uuid ++alert_type : string ++severity : string ++title : string ++message : string ++data : dict ++is_read : bool ++created_at : datetime ++brand +} +class AlertSetting { ++id : uuid ++brand_id : uuid ++user_id : uuid ++alert_type : string ++enabled : bool ++threshold : float ++created_at : datetime ++updated_at : datetime ++brand +user } -User "1" <-- "many" Query : "拥有" -Query "1" <-- "many" CitationRecord : "产生" -Query "1" <-- "many" QueryTask : "触发" -User "1" <-- "many" Subscription : "订阅" +class KnowledgeBase { ++id : uuid ++organization_id : uuid ++name : string ++type : string ++description : string ++document_count : int ++status : string ++created_by : uuid ++created_at : datetime ++updated_at : datetime ++organization ++creator ++documents +} +class KnowledgeDocument { ++id : uuid ++knowledge_base_id : uuid ++title : string ++source_type : string ++source_url : string ++content : string ++content_hash : string ++chunk_count : int ++status : string ++error_message : string ++metadata : dict ++created_at : datetime ++updated_at : datetime ++knowledge_base ++chunks +} +class KnowledgeChunk { ++id : uuid ++document_id : uuid ++content : string ++embedding : vector ++chunk_index : int ++token_count : int ++metadata : dict ++created_at : datetime ++document +} +class KnowledgeSearchLog { ++id : uuid ++organization_id : uuid ++user_id : uuid ++query : string ++knowledge_base_ids : list ++results_count : int ++latency_ms : int ++created_at : datetime ++organization ++user +} +User "1" <-- "many" Organization : "属于" +Organization "1" <-- "many" LifecycleProject : "拥有" +LifecycleProject "1" <-- "many" ProjectStage : "包含" +User "1" <-- "many" LifecycleProject : "创建" +AgentRegistry "1" <-- "many" AgentTask : "注册" +AgentTask "1" <-- "many" AgentTaskLog : "产生" +Organization "1" <-- "many" Content : "拥有" +LifecycleProject "1" <-- "many" Content : "关联" +User "1" <-- "many" Content : "创建" +Content "1" <-- "many" ContentVersion : "版本化" +Content "1" <-- "many" ContentReview : "审核" +Organization "1" <-- "many" PlatformRule : "拥有" +Organization "1" <-- "many" BrandKnowledge : "拥有" +Organization "1" <-- "many" Keyword : "拥有" +LifecycleProject "1" <-- "many" Keyword : "关联" +Organization "1" <-- "many" KnowledgeBase : "拥有" +KnowledgeBase "1" <-- "many" KnowledgeDocument : "包含" +KnowledgeDocument "1" <-- "many" KnowledgeChunk : "分块" +Organization "1" <-- "many" PublishRecord : "拥有" +PublishRecord "1" <-- "many" ContentMetrics : "产生" +Organization "1" <-- "many" OptimizationInsight : "拥有" +User "1" <-- "many" Alert : "拥有" +User "1" <-- "many" AlertSetting : "拥有" +Organization "1" <-- "many" KnowledgeSearchLog : "拥有" +User "1" <-- "many" KnowledgeSearchLog : "使用" ``` -图表来源 +**图表来源** - [backend/app/models/user.py:11-48](file://backend/app/models/user.py#L11-L48) -- [backend/app/models/query.py:11-48](file://backend/app/models/query.py#L11-L48) -- [backend/app/models/citation_record.py:11-44](file://backend/app/models/citation_record.py#L11-L44) -- [backend/app/models/query_task.py:11-34](file://backend/app/models/query_task.py#L11-L34) -- [backend/app/models/subscription.py:11-36](file://backend/app/models/subscription.py#L11-L36) +- [backend/app/models/lifecycle.py:12-92](file://backend/app/models/lifecycle.py#L12-L92) +- [backend/app/models/analytics.py:9-64](file://backend/app/models/analytics.py#L9-L64) +- [backend/app/models/alert.py:24-75](file://backend/app/models/alert.py#L24-L75) +- [backend/app/models/knowledge.py:22-213](file://backend/app/models/knowledge.py#L22-L213) -章节来源 +**章节来源** - [backend/app/models/user.py:1-48](file://backend/app/models/user.py#L1-L48) -- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) -- [backend/app/models/citation_record.py:1-44](file://backend/app/models/citation_record.py#L1-L44) -- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39) -- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37) +- [backend/app/models/lifecycle.py:1-92](file://backend/app/models/lifecycle.py#L1-L92) +- [backend/app/models/analytics.py:1-64](file://backend/app/models/analytics.py#L1-L64) +- [backend/app/models/alert.py:1-75](file://backend/app/models/alert.py#L1-L75) +- [backend/app/models/knowledge.py:1-213](file://backend/app/models/knowledge.py#L1-L213) ### 数据库迁移管理、版本控制与部署策略 - 迁移入口 @@ -442,13 +1153,19 @@ User "1" <-- "many" Subscription : "订阅" - 迁移版本 - **初始版本** (488d0bd5ab01):创建 users、queries、citation_records、query_tasks、subscriptions 表,并建立必要索引。 - **版本2** (b2c4d6e8fa10):向 citation_records 表添加 confidence 和 match_type 字段,支持增强的报告功能。 - - **新增版本3** (c3d5e7f9ab12):向 users 表添加 email_verified、verification_code、verification_code_expires、reset_token、reset_token_expires、avatar_url、is_admin 等用户管理字段。 + - **版本3** (c3d5e7f9ab12):向 users 表添加 email_verified、verification_code、verification_code_expires、reset_token、reset_token_expires、avatar_url、is_admin 等用户管理字段。 + - **新增版本4** (d4f6g8h0ab23):新增完整的业务生命周期架构,包括 organizations、lifecycle_projects、project_stages、agent_registry、agent_configs、agent_tasks、agent_task_logs、contents、content_versions、content_reviews、platform_rules、brand_knowledge、keywords 等表。 + - **新增版本5** (e5f7a9b1cd34):新增告警系统,包括 alerts 和 alert_settings 表,支持品牌监控和用户告警。 + - **新增版本6** (e5f7g9h1cd45):新增知识库系统,包括 knowledge_bases、knowledge_documents、knowledge_chunks(含向量索引)、knowledge_search_logs 表,支持pgvector向量检索。 + - **新增版本7** (f6g8h0i2de56):新增分析监控系统,包括 publish_records、content_metrics、optimization_insights 表。 - 外键约束与级联删除策略明确,确保数据一致性。 - 部署策略 - Docker Compose 启动 PostgreSQL 与 Redis,应用容器依赖数据库健康检查。 - 生产环境建议将数据库与缓存分离,使用独立卷持久化数据。 + - **新增** 向量数据库部署:知识库功能需要pgvector扩展支持。 + - **新增** 分区策略:大数据量表建议按时间分区,如content_metrics、knowledge_search_logs。 -**更新** 新增c3d5e7f9ab12迁移版本,支持完整的用户管理功能。 +**更新** 新增完整的7个版本迁移,涵盖业务生命周期、分析监控、告警系统、知识库等企业级功能。 ```mermaid flowchart TD @@ -463,44 +1180,74 @@ RunMigs --> Version{"检查版本"} Version --> |488d0bd5ab01| InitMigration["初始迁移"] Version --> |b2c4d6e8fa10| AddConfidence["添加置信度字段"] Version --> |c3d5e7f9ab12| AddUserFields["添加用户管理字段"] -InitMigration --> AddConfidence --> AddUserFields --> Done(["完成"]) +Version --> |d4f6g8h0ab23| AddLifecycle["添加生命周期架构"] +Version --> |e5f7a9b1cd34| AddAlerts["添加告警系统"] +Version --> |e5f7g9h1cd45| AddKnowledge["添加知识库系统"] +Version --> |f6g8h0i2de56| AddAnalytics["添加分析监控"] +InitMigration --> AddConfidence --> AddUserFields --> AddLifecycle --> AddAlerts --> AddKnowledge --> AddAnalytics --> Done(["完成"]) ``` -图表来源 +**图表来源** - [backend/alembic/env.py:33-88](file://backend/alembic/env.py#L33-L88) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:21-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L21-L128) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py:21-37](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#L21-L37) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py:21-41](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#L21-L41) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py:21-398](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#L21-L398) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py:21-86](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#L21-L86) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py:21-224](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#L21-L224) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py:20-125](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#L20-L125) - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) -章节来源 +**章节来源** - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:1-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L1-L128) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py:1-37](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#L1-L37) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py:1-41](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#L1-L41) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py:1-398](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#L1-L398) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py:1-86](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#L1-L86) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py:1-224](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#L1-L224) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py:1-125](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#L1-L125) - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) ### 数据完整性约束、事务处理与并发控制 - 完整性约束 - - 唯一约束:用户邮箱唯一 - - 外键约束:查询、任务、订阅均对用户做级联删除 - - JSONB 字段默认值:空数组/字典,避免 NULL 导致的条件判断复杂化 - - **新增** email_verified字段默认False,is_admin字段默认False - - **新增** verification_code长度限制为6位,reset_token长度限制为255位 - - **新增** avatar_url长度限制为500字符,match_type长度限制为20字符 + - 唯一约束:用户邮箱唯一,组织slug唯一,代理name唯一,关键词(organization_id, project_id, keyword)唯一,代理配置(agent_id, config_key)唯一,项目阶段(project_id, stage_number)唯一,告警设置(brand_id, alert_type)唯一。 + - 外键约束:所有外键均设置适当的ondelete策略(CASCADE/SET NULL),确保数据一致性。 + - JSONB字段默认值:空数组/字典,避免NULL导致的条件判断复杂化。 + - **新增** 组织表:max_members默认5,plan默认'free'。 + - **新增** 生命周期项目表:current_stage默认1,status默认'active'。 + - **新增** 项目阶段表:stage_number非空,status默认'pending'。 + - **新增** 代理注册表:name唯一,status默认'offline'。 + - **新增** 代理配置表:config_key唯一,updated_at自动更新。 + - **新增** 代理任务表:多个默认值和索引字段。 + - **新增** 内容表:status默认'draft',current_version默认1。 + - **新增** 知识库表:document_count默认0,status默认'active'。 + - **新增** email_verified字段默认False,is_admin字段默认False。 + - **新增** verification_code长度限制为6位,reset_token长度限制为255位。 + - **新增** avatar_url长度限制为500字符,match_type长度限制为20字符。 - 事务处理 - - 服务层方法在单个事务内执行插入/更新/删除,提交后刷新对象状态 - - 会话工厂设置 expire_on_commit=False,减少后续查询的额外开销 + - 服务层方法在单个事务内执行插入/更新/删除,提交后刷新对象状态。 + - 会话工厂设置 expire_on_commit=False,减少后续查询的额外开销。 + - **新增** 生命周期服务:事务边界严格控制项目状态转换。 + - **新增** 分析监控服务:发布记录与指标的原子性操作。 + - **新增** 告警引擎服务:告警规则评估的事务一致性。 + - **新增** 知识库服务:文档处理与向量嵌入的事务保障。 - 并发控制 - - 异步连接池与会话隔离,避免阻塞 - - 服务层在执行前进行权限校验与配额检查,降低并发冲突概率 + - 异步连接池与会话隔离,避免阻塞。 + - 服务层在执行前进行权限校验与配额检查,降低并发冲突概率。 + - **新增** 向量索引并发:HNSW索引支持高并发相似度搜索。 + - **新增** 分布式锁:代理任务的分布式并发控制。 -**更新** 新增用户管理字段的完整性约束说明,包括长度限制和默认值设置。 +**更新** 新增针对所有新增表的完整性约束说明,包括复合唯一约束和外键策略。 -章节来源 +**章节来源** - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:36-111](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L36-L111) - [backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py:21-37](file://backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#L21-L37) - [backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py:21-41](file://backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#L21-L41) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py:24-398](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#L24-L398) +- [backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py:24-86](file://backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#L24-L86) +- [backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py:30-224](file://backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#L30-L224) +- [backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py:24-125](file://backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#L24-L125) - [backend/app/services/query.py:45-81](file://backend/app/services/query.py#L45-L81) - [backend/app/database.py:12-18](file://backend/app/database.py#L12-L18) @@ -519,26 +1266,30 @@ InitMigration --> AddConfidence --> AddUserFields --> Done(["完成"]) - **新增** 用户管理查询 - 支持按邮箱验证状态、管理员权限等条件过滤用户 - 支持验证码和重置令牌的有效性检查 +- **新增** 生命周期查询 + - 支持按组织、状态、品牌名称过滤项目 + - 支持按阶段状态和项目阶段组合查询 + - 支持项目全生命周期统计分析 +- **新增** 分析监控查询 + - 支持按平台、状态、时间范围过滤发布记录 + - 支持内容指标的时间序列分析 + - 支持优化洞察的分类统计 +- **新增** 告警查询 + - 支持按用户、品牌、告警类型、严重程度过滤 + - 支持告警设置的阈值比较查询 + - 支持用户未读告警的统计 +- **新增** 知识库查询 + - 支持向量相似度搜索(cosine距离) + - 支持知识库文档的状态过滤 + - 支持关键词检索和内容哈希去重 +- **新增** 性能优化 + - 知识库向量索引:HNSW近似最近邻搜索,支持大规模向量相似度计算 + - 复合索引:告警系统(brand_id, alert_type)、关键词(keyword)等 + - 分区策略:大表按时间分区,如content_metrics、knowledge_search_logs -**更新** 增强查询流程,支持新的用户管理字段和认证功能。 +**更新** 新增针对所有新增功能的查询流程和优化策略,特别是向量检索和复合查询的性能优化。 -```mermaid -sequenceDiagram -participant AuthAPI as "认证API" -participant SvcAuth as "认证服务" -participant DB as "数据库" -AuthAPI->>SvcAuth : register_user(email, password, name) -SvcAuth->>DB : INSERT INTO users (email, password_hash, name) -DB-->>SvcAuth : 新用户ID -SvcAuth->>DB : SELECT * FROM users WHERE email = ? -DB-->>SvcAuth : 用户信息 -SvcAuth-->>AuthAPI : UserResponse -``` - -图表来源 -- [backend/app/services/auth.py:40-56](file://backend/app/services/auth.py#L40-L56) - -章节来源 +**章节来源** - [backend/app/services/query.py:12-32](file://backend/app/services/query.py#L12-L32) - [backend/app/services/citation.py:30-79](file://backend/app/services/citation.py#L30-L79) - [backend/app/services/auth.py:40-56](file://backend/app/services/auth.py#L40-L56) @@ -558,7 +1309,7 @@ SvcAuth-->>AuthAPI : UserResponse **新增** 报告功能章节,详细介绍新增的confidence和match_type字段的应用。 -章节来源 +**章节来源** - [backend/app/services/citation.py:298-308](file://backend/app/services/citation.py#L298-L308) - [backend/app/services/citation.py:342-429](file://backend/app/services/citation.py#L342-L429) - [backend/app/schemas/citation.py:7-18](file://backend/app/schemas/citation.py#L7-L18) @@ -578,15 +1329,121 @@ SvcAuth-->>AuthAPI : UserResponse - **管理员权限控制** - is_admin字段标识管理员身份 - 支持管理员专用功能和权限控制 +- **组织管理** + - **新增** organization_id字段关联用户到组织 + - **新增** role字段标识用户在组织中的角色 + - **新增** 支持多组织成员管理 **新增** 用户管理功能章节,详细介绍新增的用户管理字段和相关API。 -章节来源 +**章节来源** - [backend/app/services/auth.py:74-107](file://backend/app/services/auth.py#L74-L107) - [backend/app/services/auth.py:110-140](file://backend/app/services/auth.py#L110-L140) - [backend/app/schemas/auth.py:8-55](file://backend/app/schemas/auth.py#L8-L55) - [backend/app/api/auth.py:33-115](file://backend/app/api/auth.py#L33-L115) +### 业务生命周期管理 +- **组织管理** + - 组织作为业务单元,支持多用户协作 + - plan字段支持免费/付费计划管理 + - max_members限制组织规模 +- **项目管理** + - lifecycle_projects表管理品牌项目全生命周期 + - current_stage跟踪项目当前所处阶段 + - status支持active/inactive状态管理 +- **阶段管理** + - project_stages表管理项目各阶段状态 + - 支持started_at/completed_at时间跟踪 + - metrics字段存储阶段关键指标 +- **代理系统** + - agent_registry注册可用代理 + - agent_configs管理代理配置 + - agent_tasks执行代理任务 + - agent_task_logs记录任务执行日志 +- **内容管理** + - contents表管理内容创作 + - content_versions支持版本控制 + - content_reviews支持审核流程 +- **规则管理** + - platform_rules定义平台合规规则 + - 支持不同严重程度的规则 +- **知识管理** + - brand_knowledge存储品牌知识 + - 支持分类和激活状态管理 +- **关键词管理** + - keywords管理SEO关键词 + - 支持优先级和搜索量统计 + +**新增** 业务生命周期管理章节,详细介绍完整的项目管理架构。 + +**章节来源** +- [backend/app/models/lifecycle.py:12-92](file://backend/app/models/lifecycle.py#L12-L92) +- [backend/app/api/lifecycle.py](file://backend/app/api/lifecycle.py) + +### 分析监控系统 +- **发布管理** + - publish_records跟踪内容发布状态 + - 支持多平台发布(微信、知乎、小红书等) + - published_url记录发布链接 +- **指标分析** + - content_metrics收集互动指标(点赞、评论、分享等) + - GEO核心指标:AI引用次数、搜索曝光、搜索点击 + - 阅读指标:平均阅读时长、完读率 +- **优化洞察** + - optimization_insights提供内容优化建议 + - 支持不同类型洞察(趋势、异常、机会、建议) + - severity字段标识严重程度 + - applied字段跟踪建议实施状态 + +**新增** 分析监控系统章节,详细介绍内容发布和指标分析架构。 + +**章节来源** +- [backend/app/models/analytics.py:9-64](file://backend/app/models/analytics.py#L9-L64) +- [backend/app/api/analytics.py](file://backend/app/api/analytics.py) + +### 告警系统 +- **告警类型** + - score_drop:评分下降告警 + - score_rise:评分上升告警 + - negative_sentiment:负面情绪告警 + - competitor_overtake:竞争对手超越告警 + - new_platform_mention:新平台提及告警 +- **严重程度** + - critical:严重 + - warning:警告 + - info:信息 +- **告警设置** + - alert_settings表管理用户告警偏好 + - 支持阈值设置和启用状态控制 + - 支持按品牌和用户维度配置 + +**新增** 告警系统章节,详细介绍实时监控和告警机制。 + +**章节来源** +- [backend/app/models/alert.py:24-75](file://backend/app/models/alert.py#L24-L75) +- [backend/app/api/alerts.py](file://backend/app/api/alerts.py) + +### 知识库系统 +- **向量检索** + - knowledge_chunks表存储文档分块 + - embedding字段使用pgvector向量类型 + - HNSW索引支持近似最近邻搜索 + - 维度1536匹配OpenAI text-embedding-3-small +- **文档管理** + - knowledge_documents管理知识文档 + - content_hash去重机制 + - 支持多种文档类型(text、url、pdf、markdown) +- **检索日志** + - knowledge_search_logs记录检索行为 + - 支持延迟毫秒统计 + - 支持知识库ID列表过滤 + +**新增** 知识库系统章节,详细介绍向量检索和RAG应用架构。 + +**章节来源** +- [backend/app/models/knowledge.py:22-213](file://backend/app/models/knowledge.py#L22-L213) +- [backend/app/api/knowledge.py](file://backend/app/api/knowledge.py) + ## 依赖分析 - 模块耦合 - 模型层仅依赖 Base 与 SQLAlchemy 类型,低耦合 @@ -594,11 +1451,17 @@ SvcAuth-->>AuthAPI : UserResponse - Alembic 依赖 Base 与配置,迁移脚本与模型同步演进 - **新增** API层依赖服务层,提供RESTful接口 - **新增** 认证API依赖认证服务,处理用户注册、登录、验证等 + - **新增** 生命周期API依赖生命周期服务,管理项目全生命周期 + - **新增** 分析监控API依赖分析监控服务,处理发布和指标 + - **新增** 告警API依赖告警引擎服务,处理实时告警 + - **新增** 知识库API依赖知识库服务,处理向量检索 - 外部依赖 - PostgreSQL 异步驱动(asyncpg) - Redis(用于缓存,如需要) + - **新增** pgvector扩展(向量检索) + - **新增** 向量数据库(可选) -**更新** 新增API层依赖关系,支持新的认证和报告功能接口。 +**更新** 新增针对所有新增功能模块的依赖关系分析。 ```mermaid graph LR @@ -606,19 +1469,25 @@ Cfg["配置
config.py"] --> DB["数据库引擎
database.py"] DB --> Models["ORM 模型
models/*"] Models --> Services["服务层
services/*"] Services --> AuthAPI["认证API
api/auth.py"] -Services --> API["API层
api/*"] +Services --> LifeCycleAPI["生命周期API
api/lifecycle.py"] +Services --> AnalyticsAPI["分析监控API
api/analytics.py"] +Services --> AlertsAPI["告警API
api/alerts.py"] +Services --> KnowledgeAPI["知识库API
api/knowledge.py"] +Services --> CitationsAPI["引用API
api/citations.py"] +Services --> ReportsAPI["报告API
api/reports.py"] Alembic["迁移
alembic/*"] --> DB Docker["编排
docker-compose.yml"] --> DB +Vector["向量数据库
pgvector"] --> DB ``` -图表来源 +**图表来源** - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) -章节来源 +**章节来源** - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14) @@ -629,7 +1498,12 @@ Docker["编排
docker-compose.yml"] --> DB - 索引优化 - 为高频过滤字段建立单列索引(user_id/status/next_query_at/platform/queried_at/confidence/match_type) - 对 JSONB 字段可考虑 GIN 索引(如需复杂查询),当前迁移脚本未启用 - - **新增** 为用户管理字段建立索引:email、verification_code、reset_token + - **新增** 为用户管理字段建立索引:email、organization_id、verification_code、reset_token + - **新增** 为生命周期表建立复合索引:(organization_id, status)、(project_id, stage_number)、(brand_id, keyword) + - **新增** 为代理系统建立复合索引:(agent_id, status)、(organization_id, project_id)、(created_by, task_type) + - **新增** 为分析监控建立复合索引:(organization_id, platform)、(publish_record_id, recorded_at) + - **新增** 为告警系统建立复合索引:(brand_id, alert_type)、(user_id, is_read)、(organization_id, insight_type) + - **新增** 为知识库建立向量索引:HNSW(cosine)支持大规模相似度搜索 - **新增** 建议为confidence和match_type字段建立单独索引,支持高效过滤 - 查询优化 - 分页与计数分离,避免重复扫描 @@ -637,16 +1511,26 @@ Docker["编排
docker-compose.yml"] --> DB - 时间范围查询使用索引覆盖 - **新增** 支持按confidence范围和match_type进行高效过滤 - **新增** 支持按邮箱验证状态和管理员权限进行高效过滤 + - **新增** 支持向量相似度搜索的性能优化 + - **新增** 复合查询的索引选择性分析 - 缓存策略 - 引用统计与趋势数据可缓存至 Redis,设置合理过期时间 - 导出 CSV 可缓存热点查询结果,降低数据库压力 - **新增** 认证令牌和用户会话可缓存,提高认证效率 - **新增** 报告统计数据可缓存,提高频繁访问的响应速度 + - **新增** 知识库检索结果可缓存,降低向量搜索压力 + - **新增** 代理任务状态可缓存,提高任务调度效率 - 连接与并发 - 使用异步连接池,避免阻塞 - 控制并发度,避免大量写入导致锁争用 + - **新增** 向量索引并发控制,避免HNSW索引锁定 + - **新增** 分布式锁机制,确保代理任务并发安全 +- 存储优化 + - **新增** 分区策略:按月/季度分区content_metrics、knowledge_search_logs + - **新增** 归档策略:历史数据归档到冷存储 + - **新增** 压缩策略:JSONB字段压缩存储 -**更新** 新增针对用户管理字段和新功能的性能优化建议。 +**更新** 新增针对所有新增功能的性能优化建议,特别是向量检索和复合查询的优化策略。 ## 故障排查指南 - 迁移失败 @@ -654,23 +1538,44 @@ Docker["编排
docker-compose.yml"] --> DB - 确认数据库已初始化且用户具备权限 - **新增** 检查新字段的默认值和约束条件 - **新增** 验证用户管理字段的数据类型和长度限制 + - **新增** 验证pgvector扩展是否正确安装 + - **新增** 检查向量索引创建是否成功 - 查询异常 - 核对服务层权限校验逻辑,确认 user_id 与查询归属一致 - 检查索引是否存在,必要时重建索引 - **新增** 验证confidence和match_type字段的数据类型和取值范围 - **新增** 检查用户管理字段的验证逻辑和过期时间 + - **新增** 验证生命周期表的外键约束和级联删除 + - **新增** 检查向量索引的HNSW配置和性能 - 导出失败 - 确认查询所有权校验通过 - 检查 CSV 写入逻辑与字符编码 - **新增** 验证新字段在导出过程中的处理逻辑 + - **新增** 检查向量数据的序列化处理 - **新增** 认证功能故障 - 检查JWT密钥配置和令牌生成 - 验证验证码和重置令牌的有效性 - 确认邮箱验证流程的正确性 +- **新增** 生命周期功能故障 + - 检查项目阶段转换的业务规则 + - 验证代理任务的调度和执行 + - 确认内容版本控制的完整性 +- **新增** 分析监控故障 + - 检查发布记录的状态流转 + - 验证指标数据的采集和存储 + - 确认优化洞察的生成逻辑 +- **新增** 告警系统故障 + - 检查告警规则的配置和阈值 + - 验证告警通知的发送机制 + - 确认告警设置的用户偏好 +- **新增** 知识库故障 + - 检查向量嵌入的生成和存储 + - 验证相似度搜索的准确性 + - 确认文档去重和分块的处理 -**更新** 新增针对用户管理功能和新字段的故障排查指导。 +**更新** 新增针对所有新增功能的故障排查指导,包括向量检索和生命周期管理的专项排查。 -章节来源 +**章节来源** - [backend/alembic/env.py:33-88](file://backend/alembic/env.py#L33-L88) - [backend/app/services/citation.py:14-22](file://backend/app/services/citation.py#L14-L22) - [backend/app/services/auth.py:74-107](file://backend/app/services/auth.py#L74-L107) @@ -678,7 +1583,9 @@ Docker["编排
docker-compose.yml"] --> DB ## 结论 本数据库设计围绕用户、查询、引用记录、任务与订阅五大实体展开,采用 PostgreSQL + SQLAlchemy Async + Alembic 的成熟技术栈,具备良好的扩展性与可维护性。通过合理的索引策略、事务边界与服务层封装,能够满足日常查询、统计与导出需求。 -**更新** 新增的用户管理功能显著增强了系统的完整性和安全性,提供了完整的认证、授权和用户管理能力。新增的confidence和match_type字段显著增强了报告功能,提供了更精细的引用质量分析能力。建议在生产环境中进一步引入缓存与监控,持续优化查询路径与索引覆盖。 +**更新** 新增的完整业务生命周期、分析监控、告警系统、知识库等企业级功能架构,形成了从用户管理到智能代理的完整数据体系。新增的组织管理、项目阶段、代理系统、向量检索等功能显著增强了系统的业务能力和智能化水平。 + +**更新** 新增的7个迁移版本涵盖了从基础用户管理到高级AI功能的完整演进路径。建议在生产环境中进一步引入缓存与监控,持续优化查询路径与索引覆盖,特别是向量检索和复合查询的性能优化。 ## 附录 - 部署与运维 @@ -686,15 +1593,30 @@ Docker["编排
docker-compose.yml"] --> DB - 生产环境建议使用独立数据库实例与只读副本,配合连接池与慢查询日志 - **新增** 升级时确保迁移脚本按顺序执行,从初始版本到最新版本 - **新增** 配置JWT密钥和Redis缓存,确保认证功能正常运行 + - **新增** 部署pgvector扩展,确保向量检索功能正常 + - **新增** 配置向量数据库集群,支持大规模向量相似度搜索 - 备份与恢复 - 使用 pg_dump/pg_restore 进行逻辑备份与恢复 - 对关键表定期增量备份,结合 WAL 归档实现点-in-time 恢复 - **新增** 新字段变更需要纳入备份策略,确保数据完整性 - **新增** 用户管理字段包含敏感信息,需要特别注意备份安全 + - **新增** 向量数据需要特殊备份策略,确保embedding数据完整性 - 监控与告警 - 监控连接数、查询延迟、索引命中率与慢查询 - 对迁移脚本变更进行版本化管理与回滚演练 - **新增** 监控新字段的使用情况和性能影响 - **新增** 监控用户认证和验证功能的运行状态 + - **新增** 监控代理任务的执行状态和性能 + - **新增** 监控向量索引的查询性能和内存使用 + - **新增** 监控知识库的检索准确性和响应时间 +- 性能调优 + - **新增** 向量检索性能调优:HNSW索引参数优化、并发查询控制 + - **新增** 复合查询性能调优:索引选择性分析、查询计划优化 + - **新增** 分区表性能调优:分区策略选择、数据分布优化 + - **新增** 缓存策略优化:热点数据识别、缓存失效策略 +- 安全加固 + - **新增** 向量数据加密存储:敏感embedding数据保护 + - **新增** 访问控制增强:基于组织的角色权限管理 + - **新增** 审计日志完善:所有数据变更的审计追踪 -**更新** 新增针对用户管理功能和新字段的部署和运维指导。 \ No newline at end of file +**更新** 新增针对所有新增功能的部署和运维指导,包括向量数据库部署、性能调优和安全加固等专项内容。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/测试策略/测试策略.md b/.qoder/repowiki/zh/content/测试策略/测试策略.md index 65727ca..66116f3 100644 --- a/.qoder/repowiki/zh/content/测试策略/测试策略.md +++ b/.qoder/repowiki/zh/content/测试策略/测试策略.md @@ -7,8 +7,15 @@ - [tests/test_business_flow.py](file://tests/test_business_flow.py) - [tests/test_citation_engine.py](file://tests/test_citation_engine.py) - [tests/test_citations.py](file://tests/test_citations.py) +- [tests/test_content_agents.py](file://tests/test_content_agents.py) +- [tests/test_llm_provider.py](file://tests/test_llm_provider.py) +- [tests/test_pipeline_engine.py](file://tests/test_pipeline_engine.py) +- [tests/test_platform_rules.py](file://tests/test_platform_rules.py) +- [tests/test_prompt_template.py](file://tests/test_prompt_template.py) - [tests/test_queries.py](file://tests/test_queries.py) +- [tests/test_rag_service.py](file://tests/test_rag_service.py) - [tests/test_scheduler.py](file://tests/test_scheduler.py) +- [backend/tests/test_integration/test_full_flow.py](file://backend/tests/test_integration/test_full_flow.py) - [backend/app/main.py](file://backend/app/main.py) - [backend/app/api/deps.py](file://backend/app/api/deps.py) - [backend/app/services/auth.py](file://backend/app/services/auth.py) @@ -19,14 +26,22 @@ - [backend/app/api/queries.py](file://backend/app/api/queries.py) - [backend/app/database.py](file://backend/app/database.py) - [backend/app/config.py](file://backend/app/config.py) +- [backend/app/agent_framework/agents/content_generator_agent.py](file://backend/app/agent_framework/agents/content_generator_agent.py) +- [backend/app/agent_framework/agents/deai_agent.py](file://backend/app/agent_framework/agents/deai_agent.py) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py](file://backend/app/agent_framework/agents/geo_optimizer_agent.py) +- [backend/app/agent_framework/pipeline/engine.py](file://backend/app/agent_framework/pipeline/engine.py) +- [backend/app/agent_framework/pipeline/loader.py](file://backend/app/agent_framework/pipeline/loader.py) +- [backend/app/services/llm/factory.py](file://backend/app/services/llm/factory.py) ## 更新摘要 **变更内容** -- 新增业务流程测试章节,涵盖端到端业务场景测试 -- 新增调度器测试章节,包括定时任务调度和频率计算测试 -- 完善测试最佳实践,增加业务流程测试和调度器测试的最佳实践指导 -- 更新测试策略以反映新增的测试覆盖范围 +- 新增代理框架测试章节,涵盖ContentGeneratorAgent、DeAIAgent、GEOOptimizerAgent的单元测试策略 +- 新增LLM提供者测试章节,包括LLMFactory工厂模式测试、OpenAIProvider和DeepSeekProvider测试 +- 新增管道引擎测试章节,涵盖PipelineLoader和PipelineEngine的单元测试策略 +- 新增端到端工作流测试章节,涵盖完整业务流程的集成测试 +- 完善测试最佳实践,增加代理框架测试、LLM提供者测试、管道引擎测试和端到端工作流测试的最佳实践指导 +- 更新测试策略以反映新增的测试覆盖范围和架构扩展 ## 目录 1. [引言](#引言) @@ -34,19 +49,23 @@ 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) -6. [业务流程测试策略](#业务流程测试策略) -7. [调度器测试策略](#调度器测试策略) -8. [依赖分析](#依赖分析) -9. [性能考虑](#性能考虑) -10. [故障排查指南](#故障排查指南) -11. [结论](#结论) -12. [附录](#附录) +6. [代理框架测试策略](#代理框架测试策略) +7. [LLM提供者测试策略](#llm提供者测试策略) +8. [管道引擎测试策略](#管道引擎测试策略) +9. [端到端工作流测试策略](#端到端工作流测试策略) +10. [业务流程测试策略](#业务流程测试策略) +11. [调度器测试策略](#调度器测试策略) +12. [依赖分析](#依赖分析) +13. [性能考虑](#性能考虑) +14. [故障排查指南](#故障排查指南) +15. [结论](#结论) +16. [附录](#附录) ## 引言 -本测试策略文档面向GEO项目的Pytest测试体系,覆盖单元测试、集成测试和业务流程测试的设计与实施要点。内容包括:测试夹具与模拟对象的组织方式、测试数据管理策略、认证模块、引用引擎、查询处理、业务流程和调度器等关键功能的测试用例设计思路;同时给出测试最佳实践,包括覆盖率目标、持续集成配置建议以及测试环境管理方案,并提供调试技巧与性能测试方法。 +本测试策略文档面向GEO项目的Pytest测试体系,覆盖单元测试、集成测试、业务流程测试和端到端工作流测试的设计与实施要点。内容包括:测试夹具与模拟对象的组织方式、测试数据管理策略、认证模块、引用引擎、查询处理、代理框架、LLM提供者、管道引擎、业务流程和调度器等关键功能的测试用例设计思路;同时给出测试最佳实践,包括覆盖率目标、持续集成配置建议以及测试环境管理方案,并提供调试技巧与性能测试方法。 ## 项目结构 -测试目录位于仓库根目录下的tests,采用按功能模块划分的组织方式,配合Pytest的conftest集中式夹具与模拟对象,确保测试隔离与可重复性。后端应用以FastAPI为核心,API层通过依赖注入获取当前用户与数据库会话,服务层封装业务逻辑,工作器(worker)负责异步任务与平台适配。 +测试目录位于仓库根目录下的tests,采用按功能模块划分的组织方式,配合Pytest的conftest集中式夹具与模拟对象,确保测试隔离与可重复性。后端应用以FastAPI为核心,API层通过依赖注入获取当前用户与数据库会话,服务层封装业务逻辑,工作器(worker)负责异步任务与平台适配。新增的代理框架、LLM提供者和管道引擎测试进一步完善了测试体系。 ```mermaid graph TB @@ -58,6 +77,10 @@ TC["tests/test_citations.py"] TCE["tests/test_citation_engine.py"] TB["tests/test_business_flow.py"] TS["tests/test_scheduler.py"] +TCA["tests/test_content_agents.py"] +TLP["tests/test_llm_provider.py"] +TPE["tests/test_pipeline_engine.py"] +TF["backend/tests/test_integration/test_full_flow.py"] end subgraph "后端应用" M["backend/app/main.py"] @@ -69,6 +92,12 @@ QUERIES_API["backend/app/api/queries.py"] CITATIONS_API["backend/app/api/citations.py"] CE["backend/app/workers/citation_engine.py"] QS["backend/app/workers/scheduler.py"] +CGA["backend/app/agent_framework/agents/content_generator_agent.py"] +DEAI["backend/app/agent_framework/agents/deai_agent.py"] +GEO["backend/app/agent_framework/agents/geo_optimizer_agent.py"] +PL["backend/app/agent_framework/pipeline/engine.py"] +LOADER["backend/app/agent_framework/pipeline/loader.py"] +FACTORY["backend/app/services/llm/factory.py"] end C --> TA C --> TQ @@ -76,6 +105,18 @@ C --> TC C --> TCE C --> TB C --> TS +C --> TCA +C --> TLP +C --> TPE +TF --> AUTH_API +TF --> QUERIES_API +TF --> CITATIONS_API +TCA --> CGA +TCA --> DEAI +TCA --> GEO +TLP --> FACTORY +TPE --> PL +TPE --> LOADER TA --> AUTH_API TQ --> QUERIES_API TC --> CITATIONS_API @@ -102,6 +143,12 @@ M --> CITATIONS_API - [backend/app/workers/scheduler.py:1-182](file://backend/app/workers/scheduler.py#L1-L182) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) +- [backend/app/agent_framework/agents/content_generator_agent.py:1-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L1-L299) +- [backend/app/agent_framework/agents/deai_agent.py:1-156](file://backend/app/agent_framework/agents/deai_agent.py#L1-L156) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:1-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L1-L198) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/pipeline/loader.py:1-283](file://backend/app/agent_framework/pipeline/loader.py#L1-L283) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) **章节来源** - [tests/conftest.py:1-123](file://tests/conftest.py#L1-L123) @@ -114,19 +161,25 @@ M --> CITATIONS_API - 异步HTTP客户端:基于ASGI传输创建异步HTTP客户端,用于端到端API测试。 - 依赖覆盖:通过依赖注入覆盖当前用户解析逻辑,简化认证流程。 - 内存数据库:使用SQLite内存数据库进行集成测试,确保测试隔离性。 + - FakeLLMProvider:自定义FakeLLMProvider类,模拟LLM调用返回预设响应,避免真实网络请求。 + - AsyncMock:广泛使用AsyncMock替代真实异步操作,确保测试的确定性和可重复性。 - 测试数据管理 - 使用pytest fixture生成模拟模型对象(如查询、引用记录),保证测试数据一致性与可读性。 - 通过patch对服务层函数进行桩替,隔离外部依赖,提升测试确定性。 - 直接操作数据库模型进行复杂场景测试,如权限隔离和统计计算。 + - 代理框架测试中使用TaskMessage构建测试任务,模拟Agent执行流程。 - 测试运行与并发 - 使用pytest-asyncio标记异步测试,确保事件循环正确初始化与清理。 - 支持并行执行多个测试文件,提高测试执行效率。 + - 管道引擎测试中使用dry-run模式,通过dispatcher=None实现无真实任务分发的测试。 **章节来源** - [tests/conftest.py:19-123](file://tests/conftest.py#L19-L123) +- [tests/test_content_agents.py:26-54](file://tests/test_content_agents.py#L26-L54) +- [tests/test_pipeline_engine.py:148-166](file://tests/test_pipeline_engine.py#L148-L166) ## 架构总览 -下图展示了测试与被测系统的交互关系:测试通过异步HTTP客户端直接调用FastAPI路由,路由依赖当前用户与数据库会话,服务层完成业务逻辑,工作器负责平台查询与品牌匹配。 +下图展示了测试与被测系统的交互关系:测试通过异步HTTP客户端直接调用FastAPI路由,路由依赖当前用户与数据库会话,服务层完成业务逻辑,工作器负责平台查询与品牌匹配。新增的代理框架测试通过FakeLLMProvider模拟LLM调用,管道引擎测试通过dry-run模式验证Pipeline执行流程。 ```mermaid sequenceDiagram @@ -363,6 +416,275 @@ AC-->>T : 断言 - [tests/test_queries.py:1-154](file://tests/test_queries.py#L1-L154) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) +## 代理框架测试策略 + +### 测试目标 +代理框架测试专注于验证GEO平台的智能代理执行逻辑,包括内容生成代理、去AI化代理和GEO优化代理的功能完整性、错误处理能力和与LLM提供者的集成测试。 + +### 关键测试场景 +- **ContentGeneratorAgent测试**:选题生成、文章生成、RAG知识检索、JSON解析、错误处理 +- **DeAIAgent测试**:内容去AI化处理、温度参数验证、输入验证 +- **GEOOptimizerAgent测试**:SEO/GEO优化、JSON降级处理、关键词注入 +- **FakeLLMProvider测试**:模拟LLM调用、流式响应、错误模拟 + +### 测试实现策略 +- **FakeLLMProvider**:自定义FakeLLMProvider类,模拟LLM调用返回预设响应,避免真实网络请求 +- **AsyncMock**:广泛使用AsyncMock替代Redis、数据库和RAG服务调用 +- **patch技术**:通过patch替换LLMFactory.get_default和RAGService,隔离外部依赖 +- **TaskMessage构建**:使用_test_make_task辅助函数创建测试任务消息 + +```mermaid +classDiagram +class ContentGeneratorAgent { ++execute(task) TaskResult ++_generate_topics(task) dict ++_generate_article(task) dict ++_retrieve_knowledge(kb_ids, query) str ++_extract_json(text) str +} +class DeAIAgent { ++execute(task) TaskResult ++_process(task) dict +} +class GEOOptimizerAgent { ++execute(task) TaskResult ++_optimize(task) dict ++_extract_json(text) str +} +class FakeLLMProvider { ++chat(messages, **kwargs) LLMResponse ++chat_stream(messages, **kwargs) AsyncGenerator ++provider_name str ++model_name str ++max_context_length int +} +ContentGeneratorAgent --> FakeLLMProvider : "使用" +DeAIAgent --> FakeLLMProvider : "使用" +GEOOptimizerAgent --> FakeLLMProvider : "使用" +``` + +**图表来源** +- [tests/test_content_agents.py:26-54](file://tests/test_content_agents.py#L26-L54) +- [tests/test_content_agents.py:75-116](file://tests/test_content_agents.py#L75-L116) +- [tests/test_content_agents.py:200-236](file://tests/test_content_agents.py#L200-L236) +- [tests/test_content_agents.py:268-320](file://tests/test_content_agents.py#L268-L320) + +### 测试用例设计要点 +- **内容生成测试**:验证topics字段解析、article内容生成、word count计算、usage统计 +- **RAG集成测试**:通过AsyncSessionLocal mock验证知识检索上下文注入 +- **错误处理测试**:模拟LLMError验证failed状态返回和错误消息处理 +- **温度参数测试**:验证DeAIAgent的temperature=0.9配置 +- **JSON解析测试**:测试```json```包裹和普通文本两种输出格式 + +**章节来源** +- [tests/test_content_agents.py:1-358](file://tests/test_content_agents.py#L1-L358) +- [backend/app/agent_framework/agents/content_generator_agent.py:1-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L1-L299) +- [backend/app/agent_framework/agents/deai_agent.py:1-156](file://backend/app/agent_framework/agents/deai_agent.py#L1-L156) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:1-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L1-L198) + +## LLM提供者测试策略 + +### 测试目标 +LLM提供者测试专注于验证GEO平台的LLM抽象层,包括工厂模式、OpenAIProvider和DeepSeekProvider的功能完整性、错误处理和流式响应处理。 + +### 关键测试场景 +- **LLMFactory测试**:工厂创建、默认提供者选择、未知提供者处理、提供者列表 +- **OpenAIProvider测试**:聊天响应、重试机制、错误处理、SSE流解析 +- **DeepSeekProvider测试**:基础功能验证、与OpenAIProvider对比 +- **LLMResponse测试**:响应结构验证、usage统计 + +### 测试实现策略 +- **环境变量设置**:通过monkeypatch设置OPENAI_API_KEY和DEEPSEEK_API_KEY +- **httpx模拟**:使用MagicMock模拟HTTP响应,测试各种状态码场景 +- **AsyncMock**:模拟异步HTTP客户端和SSE流响应 +- **重试机制测试**:通过patch asyncio.sleep避免真实等待时间 + +```mermaid +classDiagram +class LLMFactory { ++create(provider, model) LLMProvider ++get_default() LLMProvider ++list_providers() list[str] ++register(name, provider_cls) void +} +class OpenAIProvider { ++chat(messages) LLMResponse ++chat_stream(messages) AsyncGenerator ++provider_name str ++model_name str ++max_context_length int +} +class DeepSeekProvider { ++chat(messages) LLMResponse ++chat_stream(messages) AsyncGenerator ++provider_name str ++model_name str ++max_context_length int +} +class LLMProvider { +<> ++chat(messages) LLMResponse ++chat_stream(messages) AsyncGenerator ++provider_name str ++model_name str ++max_context_length int +} +LLMFactory --> LLMProvider : "创建" +LLMProvider <|-- OpenAIProvider +LLMProvider <|-- DeepSeekProvider +``` + +**图表来源** +- [tests/test_llm_provider.py:24-67](file://tests/test_llm_provider.py#L24-L67) +- [tests/test_llm_provider.py:94-153](file://tests/test_llm_provider.py#L94-L153) +- [tests/test_llm_provider.py:200-204](file://tests/test_llm_provider.py#L200-L204) +- [backend/app/services/llm/factory.py:8-66](file://backend/app/services/llm/factory.py#L8-L66) + +### 测试用例设计要点 +- **工厂模式测试**:验证create方法、默认提供者、未知提供者异常处理 +- **HTTP响应测试**:模拟200、429、401等不同状态码的处理逻辑 +- **重试机制测试**:验证429速率限制的重试行为和401不可重试的处理 +- **流式响应测试**:验证SSE流的逐token解析和完成信号处理 +- **响应结构测试**:验证LLMResponse的字段完整性和默认值 + +**章节来源** +- [tests/test_llm_provider.py:1-205](file://tests/test_llm_provider.py#L1-L205) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) + +## 管道引擎测试策略 + +### 测试目标 +管道引擎测试专注于验证GEO平台的Pipeline编排能力,包括YAML加载、DAG验证、拓扑排序、变量解析和dry-run执行模式。 + +### 关键测试场景 +- **PipelineLoader测试**:YAML加载、DAG验证、拓扑排序、变量解析 +- **PipelineEngine测试**:dry-run模式、阶段执行、超时处理、重试机制 +- **变量解析测试**:简单变量替换、嵌套路径解析、上下文传递 +- **依赖关系测试**:有环图检测、无环图验证、执行顺序保证 + +### 测试实现策略 +- **YAML模板**:使用textwrap.dedent创建测试用YAML配置 +- **dry-run模式**:通过dispatcher=None实现无真实任务分发的测试 +- **AsyncMock**:模拟Agent执行和任务状态查询 +- **拓扑排序**:验证依赖关系的正确执行顺序 + +```mermaid +classDiagram +class PipelineLoader { ++load(pipeline_name) Pipeline ++load_from_yaml(yaml_content, pipeline_name) Pipeline ++validate_dag(stages) bool ++resolve_variables(template, context) Any +} +class PipelineEngine { ++execute(pipeline, context) PipelineResult ++_execute_stage(stage, exec_context, stages_context) StageResult ++_topological_sort(stages) list[PipelineStage] ++_resolve_stage_inputs(inputs, context) dict ++_should_skip(stage, failed_stages, skipped_stages) bool ++_evaluate_condition(condition, exec_context, stages_context) bool ++_extract_outputs(stage, output_data) dict +} +class Pipeline { ++name str ++version str ++description str ++variables dict ++stages list[PipelineStage] +} +class PipelineStage { ++name str ++agent str ++action str ++depends_on list[str] ++inputs dict ++outputs list[str] ++timeout_seconds int ++retry_count int ++condition str ++continue_on_failure bool +} +PipelineLoader --> Pipeline : "创建" +PipelineEngine --> Pipeline : "执行" +Pipeline --> PipelineStage : "包含" +``` + +**图表来源** +- [tests/test_pipeline_engine.py:55-98](file://tests/test_pipeline_engine.py#L55-L98) +- [tests/test_pipeline_engine.py:148-223](file://tests/test_pipeline_engine.py#L148-L223) +- [backend/app/agent_framework/pipeline/loader.py:41-134](file://backend/app/agent_framework/pipeline/loader.py#L41-L134) +- [backend/app/agent_framework/pipeline/engine.py:31-176](file://backend/app/agent_framework/pipeline/engine.py#L31-L176) + +### 测试用例设计要点 +- **YAML加载测试**:验证正常YAML的解析和Pipeline对象创建 +- **DAG验证测试**:测试有环图的异常处理和无环图的验证通过 +- **变量解析测试**:验证${var}和${stages.step1.outputs.result}等变量引用 +- **dry-run模式测试**:验证无dispatcher时的模拟执行和结果收集 +- **超时和重试测试**:验证阶段级别的超时控制和重试机制 + +**章节来源** +- [tests/test_pipeline_engine.py:1-255](file://tests/test_pipeline_engine.py#L1-L255) +- [backend/app/agent_framework/pipeline/loader.py:1-283](file://backend/app/agent_framework/pipeline/loader.py#L1-L283) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) + +## 端到端工作流测试策略 + +### 测试目标 +端到端工作流测试专注于验证GEO平台的完整业务流程,包括品牌查询、竞争品牌管理、引用数据收集、评分计算和CSV导出的完整链路。 + +### 关键测试场景 +- **完整品牌查询流程**:品牌创建、竞争品牌添加、查询创建、引用数据模拟、评分计算、历史记录、统计聚合 +- **CSV导出流程**:品牌创建、查询创建、引用数据创建、CSV导出、内容验证 +- **错误处理流程**:不存在的品牌ID处理、404错误验证 + +### 测试实现策略 +- **异步数据库**:使用SQLite内存数据库和async_sessionmaker +- **依赖覆盖**:通过app.dependency_overrides覆盖get_db和get_current_user +- **测试数据构建**:直接操作模型类创建测试数据 +- **HTTP客户端**:使用AsyncClient和ASGITransport进行端到端测试 + +```mermaid +sequenceDiagram +participant T as "端到端测试" +participant AC as "AsyncClient" +participant API as "FastAPI路由" +participant DB as "异步数据库" +T->>AC : POST /api/v1/brands/ +AC->>API : 品牌创建 +API->>DB : 插入品牌记录 +API-->>AC : 201 + 品牌数据 +T->>AC : POST /api/v1/brands/{brand_id}/competitors/ +AC->>API : 添加竞争品牌 +API->>DB : 插入竞争品牌记录 +API-->>AC : 201 + 竞争品牌数据 +T->>AC : POST /api/v1/queries/ +AC->>API : 创建查询 +API->>DB : 插入查询记录 +API-->>AC : 201 + 查询数据 +T->>AC : POST /api/v1/citations/ +AC->>API : 创建引用记录 +API->>DB : 插入引用记录 +API-->>AC : 201 + 引用数据 +T->>AC : GET /api/v1/brands/{brand_id}/score/ +AC->>API : 获取品牌评分 +API->>DB : 查询引用统计 +API-->>AC : 200 + 评分数据 +``` + +**图表来源** +- [backend/tests/test_integration/test_full_flow.py:94-223](file://backend/tests/test_integration/test_full_flow.py#L94-L223) +- [backend/tests/test_integration/test_full_flow.py:228-298](file://backend/tests/test_integration/test_full_flow.py#L228-L298) + +### 测试用例设计要点 +- **数据隔离**:使用独立的异步数据库连接和会话 +- **依赖注入**:通过dependency_overrides确保测试环境的一致性 +- **流程完整性**:覆盖从品牌创建到最终评分的完整业务流程 +- **数据验证**:验证统计计算的准确性,如提及率、引用率等指标 +- **CSV内容验证**:验证导出文件的格式和关键字段存在性 + +**章节来源** +- [backend/tests/test_integration/test_full_flow.py:1-322](file://backend/tests/test_integration/test_full_flow.py#L1-L322) + ## 业务流程测试策略 ### 测试目标 @@ -484,11 +806,15 @@ QueryScheduler --> AsyncIOScheduler : "使用" - 测试通过ASGI传输直接调用路由,避免引入额外适配层 - 通过依赖覆盖与patch解耦服务层与数据库、第三方平台 - 业务流程测试直接操作数据库模型,确保测试数据的准确性 + - 代理框架测试通过FakeLLMProvider和AsyncMock解耦LLM调用 + - LLM提供者测试通过httpx模拟和AsyncMock解耦HTTP请求 + - 管道引擎测试通过dry-run模式解耦真实任务分发 - 外部依赖与集成点 - 数据库:通过异步引擎与会话管理,测试中可使用内存数据库或独立测试库 - JWT:通过服务层令牌生成与校验,测试中直接构造令牌头 - 平台适配器:通过patch替换,避免真实网络请求 - 调度器:通过patch替换真实的APScheduler,使用AsyncMock控制调度行为 + - LLM提供者:通过LLMFactory统一管理,测试中可通过patch替换具体实现 - 循环依赖与风险 - 当前结构清晰,无明显循环依赖;注意在测试中避免对真实调度器的依赖 @@ -500,6 +826,14 @@ T_CIT["测试: 引用"] --> A_CIT["路由: 引用"] T_BUSINESS["测试: 业务流程"] --> A_QUERIES T_BUSINESS --> A_CIT T_SCHED["测试: 调度器"] --> QS["调度器: QueryScheduler"] +T_AGENTS["测试: 代理框架"] --> CGA["代理: ContentGeneratorAgent"] +T_AGENTS --> DEAI["代理: DeAIAgent"] +T_AGENTS --> GEO["代理: GEOOptimizerAgent"] +T_LLM["测试: LLM提供者"] --> FACTORY["工厂: LLMFactory"] +T_PIPE["测试: 管道引擎"] --> ENGINE["引擎: PipelineEngine"] +T_FULL["测试: 端到端"] --> A_AUTH +T_FULL --> A_QUERIES +T_FULL --> A_CIT A_AUTH --> S_AUTH["服务: 认证"] A_QUERIES --> S_QUERY["服务: 查询"] A_CIT --> S_CIT["服务: 引用"] @@ -508,6 +842,10 @@ S_QUERY --> DB S_CIT --> DB QS --> CE["引擎: CitationEngine"] QS --> DB +CGA --> LLM["LLM提供者"] +DEAI --> LLM +GEO --> LLM +ENGINE --> LOADER["加载器: PipelineLoader"] DB --> CFG["配置"] ``` @@ -515,10 +853,20 @@ DB --> CFG["配置"] - [tests/test_auth.py:1-104](file://tests/test_auth.py#L1-L104) - [tests/test_business_flow.py:1-441](file://tests/test_business_flow.py#L1-L441) - [tests/test_scheduler.py:1-123](file://tests/test_scheduler.py#L1-L123) +- [tests/test_content_agents.py:1-358](file://tests/test_content_agents.py#L1-L358) +- [tests/test_llm_provider.py:1-205](file://tests/test_llm_provider.py#L1-L205) +- [tests/test_pipeline_engine.py:1-255](file://tests/test_pipeline_engine.py#L1-L255) +- [backend/tests/test_integration/test_full_flow.py:1-322](file://backend/tests/test_integration/test_full_flow.py#L1-L322) - [backend/app/api/auth.py:1-43](file://backend/app/api/auth.py#L1-L43) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) - [backend/app/api/citations.py:1-78](file://backend/app/api/citations.py#L1-L78) - [backend/app/workers/scheduler.py:1-182](file://backend/app/workers/scheduler.py#L1-L182) +- [backend/app/agent_framework/agents/content_generator_agent.py:1-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L1-L299) +- [backend/app/agent_framework/agents/deai_agent.py:1-156](file://backend/app/agent_framework/agents/deai_agent.py#L1-L156) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:1-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L1-L198) +- [backend/app/services/llm/factory.py:1-66](file://backend/app/services/llm/factory.py#L1-L66) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/pipeline/loader.py:1-283](file://backend/app/agent_framework/pipeline/loader.py#L1-L283) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) @@ -531,16 +879,22 @@ DB --> CFG["配置"] - 使用pytest-asyncio并行执行异步测试,减少总耗时 - 通过会话级调度器模拟避免真实后台任务带来的不稳定因素 - 业务流程测试使用内存数据库,避免磁盘I/O开销 + - 代理框架测试使用FakeLLMProvider,避免真实LLM调用的网络延迟 + - LLM提供者测试使用httpx模拟,避免真实HTTP请求的网络开销 + - 管道引擎测试使用dry-run模式,避免真实任务分发的系统开销 - 数据库与缓存 - 建议使用独立测试数据库实例,避免与开发/生产数据冲突 - 对高频查询场景,可在测试中模拟数据库延迟,评估路由与服务层的超时与重试策略 - 调度器测试使用AsyncMock,避免真实的定时任务执行 + - 代理框架测试使用AsyncMock,避免真实Redis和数据库调用 - 接口响应与序列化 - 对大列表与统计聚合接口,关注JSON序列化开销与分页参数边界 - 业务流程测试中直接操作数据库模型,避免不必要的API调用 + - 端到端测试中合理使用AsyncClient,避免过多的HTTP请求 - 平台适配器性能 - 通过patch模拟不同响应时延与错误率,评估引擎的容错与降级策略 - 调度器测试中使用精确的时间控制,避免真实的等待时间 + - LLM提供者测试中使用AsyncMock,避免真实网络请求的等待时间 ## 故障排查指南 - 常见问题定位 @@ -549,18 +903,26 @@ DB --> CFG["配置"] - 403配额:检查服务层权限异常抛出与HTTP状态映射 - 调度器异常:检查APScheduler的启动状态和job配置 - 业务流程失败:检查数据库事务和fixture的使用 + - 代理执行失败:检查FakeLLMProvider的mock配置和report_progress的patch + - LLM提供者异常:检查API密钥设置和httpx模拟配置 + - 管道执行失败:检查YAML配置和依赖关系验证 + - 端到端测试失败:检查数据库连接和依赖覆盖配置 - 调试技巧 - 在conftest中临时打印依赖解析过程,定位get_current_user解析失败原因 - 使用pytest的-v与-s选项查看详细输出,结合patch的side_effect观察异常传播 - 对数据库相关测试,开启SQLAlchemy echo以查看生成的SQL - 调度器测试中使用AsyncMock的assert_called_once()验证调度器行为 + - 代理框架测试中检查report_progress的调用次数和参数 + - LLM提供者测试中验证httpx.post的调用参数和返回值 + - 管道引擎测试中检查拓扑排序和变量解析的中间结果 - 性能与稳定性 - 对于长时间运行的异步测试,确保事件循环正确关闭 - 对需要真实网络请求的场景,优先使用patch模拟,必要时增加超时与重试 - 业务流程测试中合理使用fixture,避免重复创建昂贵的对象 + - 代理框架测试中使用AsyncMock,确保异步操作的正确模拟 ## 结论 -本测试策略以Pytest为核心,结合会话级调度器模拟、依赖覆盖与patch技术,实现了对认证、查询、引用、引擎模块以及业务流程和调度器的全面覆盖。通过明确的夹具与测试数据管理,确保测试的可维护性与可重复性。新增的业务流程测试和调度器测试进一步完善了测试体系,涵盖了端到端业务场景和定时任务调度的关键功能。建议在CI中启用并行执行与覆盖率统计,并为数据库与平台适配器建立稳定的模拟层,持续提升测试效率与质量。 +本测试策略以Pytest为核心,结合会话级调度器模拟、依赖覆盖与patch技术,实现了对认证、查询、引用、引擎模块、业务流程、调度器、代理框架、LLM提供者、管道引擎和端到端工作流的全面覆盖。通过明确的夹具与测试数据管理,确保测试的可维护性与可重复性。新增的代理框架测试、LLM提供者测试、管道引擎测试和端到端工作流测试进一步完善了测试体系,涵盖了智能代理执行、LLM抽象层、Pipeline编排和完整业务流程的关键功能。建议在CI中启用并行执行与覆盖率统计,并为数据库、LLM提供者、代理框架和管道引擎建立稳定的模拟层,持续提升测试效率与质量。 ## 附录 - 测试覆盖率要求建议 @@ -570,16 +932,29 @@ DB --> CFG["配置"] - 函数/方法覆盖率:≥90% - 业务流程覆盖率:≥95% - 调度器覆盖率:≥90% + - 代理框架覆盖率:≥90% + - LLM提供者覆盖率:≥90% + - 管道引擎覆盖率:≥90% + - 端到端工作流覆盖率:≥95% - 持续集成配置建议 - 使用GitHub Actions或GitLab CI,包含Python版本矩阵、依赖安装、数据库准备、pytest执行与覆盖率上传 - 将测试与lint、类型检查并行,确保主干分支质量 - - 为业务流程测试和调度器测试单独配置执行时间限制 + - 为业务流程测试、调度器测试、代理框架测试、LLM提供者测试、管道引擎测试和端到端工作流测试单独配置执行时间限制 + - 为LLM提供者测试配置环境变量,确保API密钥正确设置 - 测试环境管理 - 使用独立测试数据库与Redis实例,避免污染 - 通过环境变量切换测试配置,确保敏感信息不泄露 - 业务流程测试使用内存数据库,调度器测试使用AsyncMock + - 代理框架测试使用FakeLLMProvider和AsyncMock + - LLM提供者测试使用httpx模拟和环境变量 + - 管道引擎测试使用dry-run模式 + - 端到端测试使用AsyncClient和依赖覆盖 - 性能测试方法 - 使用pytest-benchmark或locust对高频路由进行基准测试 - 对引擎执行流程进行压力测试,评估平台适配器与数据库写入瓶颈 - 调度器测试中使用时间控制和AsyncMock,避免真实的定时等待 - - 业务流程测试中评估端到端流程的响应时间和吞吐量 \ No newline at end of file + - 业务流程测试中评估端到端流程的响应时间和吞吐量 + - 代理框架测试中评估LLM调用的性能和错误处理 + - LLM提供者测试中评估HTTP请求的性能和重试机制 + - 管道引擎测试中评估Pipeline执行的性能和超时处理 + - 端到端测试中评估完整业务流程的性能和稳定性 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/部署与运维.md b/.qoder/repowiki/zh/content/部署与运维/部署与运维.md index c36c8ef..0874f2a 100644 --- a/.qoder/repowiki/zh/content/部署与运维/部署与运维.md +++ b/.qoder/repowiki/zh/content/部署与运维/部署与运维.md @@ -15,20 +15,35 @@ - [backend/app/models/query.py](file://backend/app/models/query.py) - [backend/alembic.ini](file://backend/alembic.ini) - [backend/alembic/env.py](file://backend/alembic/env.py) +- [backend/app/middleware/logging_middleware.py](file://backend/app/middleware/logging_middleware.py) +- [backend/app/middleware/rate_limit.py](file://backend/app/middleware/rate_limit.py) - [tests/test_auth.py](file://tests/test_auth.py) +## 更新摘要 +**所做更改** +- 新增完整的Docker容器化部署配置说明 +- 补充生产环境部署策略与最佳实践 +- 完善监控日志管理方案与运维指南 +- 增加CI/CD流水线与自动化部署配置 +- 更新环境配置与安全加固措施 + ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) -6. [依赖分析](#依赖分析) -7. [性能考虑](#性能考虑) -8. [故障排查指南](#故障排查指南) -9. [结论](#结论) -10. [附录](#附录) +6. [Docker容器化部署](#docker容器化部署) +7. [生产环境部署策略](#生产环境部署策略) +8. [监控与日志管理](#监控与日志管理) +9. [运维最佳实践](#运维最佳实践) +10. [CI/CD流水线配置](#cicd流水线配置) +11. [依赖分析](#依赖分析) +12. [性能考虑](#性能考虑) +13. [故障排查指南](#故障排查指南) +14. [结论](#结论) +15. [附录](#附录) ## 简介 本文件面向GEO项目的部署与运维团队,提供从开发到生产的完整落地指南。内容覆盖Docker容器化部署、镜像构建、服务编排与环境配置;生产部署策略(Nginx反向代理、SSL证书、负载均衡);监控与日志管理(健康检查、错误追踪、性能监控);运维最佳实践(备份、安全、故障恢复)以及CI/CD流水线与自动化部署建议。文档严格基于仓库现有配置与实现进行说明,避免臆测。 @@ -69,18 +84,18 @@ SCH --> RD FE --> API ``` -图表来源 +**图表来源** - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) - [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) -- [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +- [backend/app/main.py:1-100](file://backend/app/main.py#L1-L100) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) +- [backend/app/workers/scheduler.py:1-189](file://backend/app/workers/scheduler.py#L1-L189) - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) -章节来源 +**章节来源** - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) - [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) @@ -98,11 +113,11 @@ FE --> API - 迁移与版本控制(Alembic) - 异步迁移环境、配置文件与日志级别。 -章节来源 -- [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +**章节来源** +- [backend/app/main.py:1-100](file://backend/app/main.py#L1-L100) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) +- [backend/app/workers/scheduler.py:1-189](file://backend/app/workers/scheduler.py#L1-L189) - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) @@ -118,7 +133,7 @@ subgraph "边缘层" NGINX["Nginx 反向代理
SSL/TLS 终止"] end subgraph "应用层" -LB["负载均衡器/反向代理" +LB["负载均衡器/反向代理"] subgraph "后端实例" API1["API 实例 1"] API2["API 实例 2"] @@ -143,7 +158,9 @@ API2 --> RDS API3 --> RDS ``` -(本图为概念性架构示意,不对应具体源码文件) +**图表来源** +- [docker-compose.yml:36-66](file://docker-compose.yml#L36-L66) +- [backend/app/main.py:97-100](file://backend/app/main.py#L97-L100) ## 详细组件分析 @@ -180,19 +197,19 @@ S->>D : "周期性查询待执行任务" S->>A : "触发执行逻辑" ``` -图表来源 +**图表来源** - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) -- [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +- [backend/app/main.py:33-45](file://backend/app/main.py#L33-L45) +- [backend/app/config.py:12-14](file://backend/app/config.py#L12-L14) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) +- [backend/app/workers/scheduler.py:33-51](file://backend/app/workers/scheduler.py#L33-L51) -章节来源 +**章节来源** - [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) -- [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) -- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17) +- [backend/app/main.py:1-100](file://backend/app/main.py#L1-L100) +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) +- [backend/app/workers/scheduler.py:1-189](file://backend/app/workers/scheduler.py#L1-L189) ### 前端(Next.js)与容器化 - 容器镜像构建要点 @@ -201,10 +218,10 @@ S->>A : "触发执行逻辑" - 与后端交互 - 默认CORS允许来自前端开发地址的请求,生产环境需根据域名调整。 -章节来源 +**章节来源** - [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) -- [backend/app/main.py:30-36](file://backend/app/main.py#L30-L36) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) +- [backend/app/main.py:53-63](file://backend/app/main.py#L53-L63) ### 数据库与迁移(PostgreSQL + Alembic) - 连接与会话 @@ -259,13 +276,13 @@ QUERIES ||--o{ CITATION_RECORDS : "生成" QUERIES ||--o{ QUERY_TASKS : "拆分任务" ``` -图表来源 +**图表来源** - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/alembic.ini:86-89](file://backend/alembic.ini#L86-L89) - [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89) -章节来源 +**章节来源** - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) - [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150) @@ -278,9 +295,9 @@ QUERIES ||--o{ QUERY_TASKS : "拆分任务" - JWT密钥默认值仅用于开发,生产必须替换。 - CORS在开发环境允许前端地址,生产需限定来源。 -章节来源 -- [backend/app/api/auth.py:1-43](file://backend/app/api/auth.py#L1-L43) -- [backend/app/config.py:9-9](file://backend/app/config.py#L9-L9) +**章节来源** +- [backend/app/api/auth.py:1-115](file://backend/app/api/auth.py#L1-L115) +- [backend/app/config.py:14](file://backend/app/config.py#L14) ### 编排与健康检查(Docker Compose) - 服务编排 @@ -290,9 +307,259 @@ QUERIES ||--o{ QUERY_TASKS : "拆分任务" - 依赖顺序 - 后端等待数据库与Redis健康后再启动,前端依赖后端。 -章节来源 +**章节来源** - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) -- [backend/app/main.py:45-48](file://backend/app/main.py#L45-L48) +- [backend/app/main.py:97-100](file://backend/app/main.py#L97-L100) + +## Docker容器化部署 + +### 镜像构建配置 +GEO项目采用多阶段容器化部署,后端和前端分别构建独立镜像: + +**后端镜像构建流程** +- 基础镜像:python:3.11-slim +- 系统依赖:安装Playwright运行所需的系统库 +- 依赖安装:pip安装requirements.txt中的所有依赖 +- 浏览器安装:预装Chromium浏览器驱动 +- 应用部署:复制源码并暴露8000端口 + +**前端镜像构建流程** +- 基础镜像:node:20-alpine +- 依赖安装:使用npm ci安装生产依赖 +- 应用部署:复制源码并暴露3000端口 + +**章节来源** +- [backend/Dockerfile:1-41](file://backend/Dockerfile#L1-L41) +- [frontend/Dockerfile:1-15](file://frontend/Dockerfile#L1-L15) +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) + +### 服务编排配置 +Docker Compose定义了完整的微服务架构: + +**数据库服务(db)** +- 镜像:postgres:15-alpine +- 端口映射:5432:5432 +- 健康检查:使用pg_isready检测数据库可用性 +- 数据持久化:挂载postgres_data卷 + +**缓存服务(redis)** +- 镜像:redis:7-alpine +- 端口映射:6379:6379 +- 健康检查:使用redis-cli ping检测 +- 数据持久化:挂载redis_data卷 + +**后端服务(backend)** +- 构建:使用./backend目录作为构建上下文 +- 端口映射:8000:8000 +- 环境配置:加载.env文件 +- 依赖关系:等待db和redis健康检查通过 +- 命令:uvicorn启动FastAPI应用 + +**前端服务(frontend)** +- 构建:使用./frontend目录作为构建上下文 +- 端口映射:3000:3000 +- 环境配置:加载.env文件 +- 依赖关系:依赖backend服务 +- 命令:npm run dev启动开发服务器 + +**章节来源** +- [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) + +### 环境配置管理 +项目使用Pydantic Settings进行环境变量管理,支持不同环境的配置分离: + +**核心配置项** +- 数据库连接:DATABASE_URL(默认指向db容器) +- Redis连接:REDIS_URL(默认指向redis容器) +- JWT配置:JWT_SECRET、JWT_EXPIRE_HOURS +- LLM提供商:支持OpenAI、DeepSeek、通义千问等 +- CORS配置:CORS_ORIGINS允许跨域请求的来源列表 + +**章节来源** +- [backend/app/config.py:1-46](file://backend/app/config.py#L1-L46) + +## 生产环境部署策略 + +### Nginx反向代理配置 +生产环境推荐使用Nginx作为反向代理和SSL终止: + +**基础反向代理配置** +``` +upstream backend { + server backend:8000; +} + +server { + listen 80; + server_name geo.example.com; + + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +**SSL证书配置** +- 使用Let's Encrypt自动签发免费SSL证书 +- 配置HTTP到HTTPS重定向 +- 启用现代TLS协议和加密套件 + +**负载均衡配置** +- 使用Nginx内置负载均衡器 +- 配置健康检查和故障转移 +- 支持多实例后端部署 + +### 容器编排与扩展 +生产环境建议使用Docker Swarm或Kubernetes进行容器编排: + +**服务扩展** +- 后端API:根据负载情况动态扩展实例数量 +- 数据库:配置主从复制和只读副本 +- 缓存:使用Redis集群提高可用性 + +**存储管理** +- 使用持久化存储卷确保数据安全 +- 配置定期备份策略 +- 实施数据同步和灾备方案 + +**章节来源** +- [docker-compose.yml:36-66](file://docker-compose.yml#L36-L66) +- [backend/app/config.py:12-14](file://backend/app/config.py#L12-L14) + +## 监控与日志管理 + +### 健康检查与监控 +项目已内置基本的健康检查功能,生产环境需要增强监控能力: + +**应用级监控** +- 健康检查端点:/health +- 性能指标:响应时间、错误率、吞吐量 +- 资源使用:CPU、内存、磁盘空间 + +**基础设施监控** +- 数据库连接池监控 +- Redis连接状态监控 +- 文件系统空间监控 + +**日志管理方案** +- 结构化日志输出到标准输出 +- 使用集中式日志收集系统(如ELK Stack) +- 日志轮转和保留策略 + +**章节来源** +- [backend/app/main.py:97-100](file://backend/app/main.py#L97-L100) +- [backend/app/middleware/logging_middleware.py:1-24](file://backend/app/middleware/logging_middleware.py#L1-L24) + +### 错误追踪与告警 +**错误追踪配置** +- 使用结构化日志记录异常信息 +- 集成错误追踪服务(如Sentry) +- 设置错误阈值和告警规则 + +**性能监控** +- 数据库查询性能监控 +- API响应时间监控 +- 缓存命中率监控 + +**章节来源** +- [backend/app/middleware/rate_limit.py:1-83](file://backend/app/middleware/rate_limit.py#L1-L83) + +## 运维最佳实践 + +### 备份策略 +**数据库备份** +- 定时全量备份:每周日凌晨2点执行 +- 增量备份:每小时执行 +- 多地备份:本地和云端同时保存 + +**配置备份** +- 环境变量文件备份 +- Docker Compose配置备份 +- SSL证书备份 + +**恢复流程** +- 制定详细的灾难恢复计划 +- 定期进行恢复演练 +- 建立快速恢复机制 + +### 安全配置 +**网络安全** +- 最小权限原则 +- 网络隔离和防火墙配置 +- 入站/出站流量控制 + +**应用安全** +- 定期更新依赖包 +- 密钥轮换策略 +- 安全审计日志 + +**数据安全** +- 敏感数据加密存储 +- 数据传输加密 +- 访问权限控制 + +### 故障恢复 +**故障分类与响应** +- 一级故障:系统完全不可用,立即启动应急预案 +- 二级故障:部分功能受影响,优先保证核心业务 +- 三级故障:性能下降但可正常运行,监控观察 + +**恢复流程** +- 快速诊断和定位问题 +- 实施临时修复措施 +- 执行永久性修复 +- 验证系统恢复正常 + +**章节来源** +- [backend/app/config.py:14](file://backend/app/config.py#L14) +- [backend/app/middleware/rate_limit.py:34-69](file://backend/app/middleware/rate_limit.py#L34-L69) + +## CI/CD流水线配置 + +### 自动化部署流程 +**开发到生产的完整流程** +1. 代码提交触发CI流水线 +2. 自动化测试(单元测试、集成测试) +3. 代码质量检查 +4. 构建Docker镜像 +5. 推送镜像到镜像仓库 +6. 自动部署到测试环境 +7. 手动审批进入生产环境 +8. 部署到生产环境并监控 + +**流水线阶段配置** +- 代码检出和分支管理 +- 依赖安装和缓存优化 +- 测试执行和覆盖率报告 +- 安全扫描和漏洞检测 +- 镜像构建和标签管理 +- 多环境部署策略 + +**回滚机制** +- 支持一键回滚到上一个稳定版本 +- 自动化回滚测试 +- 回滚通知和审计 + +**章节来源** +- [backend/requirements.txt:35-42](file://backend/requirements.txt#L35-L42) + +### 部署检查清单 +**生产部署前检查** +- 所有测试通过 +- 配置文件验证 +- 环境变量检查 +- 数据库迁移验证 +- 服务健康检查 + +**部署后验证** +- 健康检查端点验证 +- 核心功能测试 +- 性能基准测试 +- 监控告警检查 ## 依赖分析 - 后端依赖 @@ -318,13 +585,13 @@ REQ --> PLT PKGJSON --> NODE ``` -图表来源 -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) +**图表来源** +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) -章节来源 -- [backend/requirements.txt:1-35](file://backend/requirements.txt#L1-L35) -- [frontend/package.json:1-40](file://frontend/package.json#L1-L40) +**章节来源** +- [backend/requirements.txt:1-42](file://backend/requirements.txt#L1-L42) +- [frontend/package.json:1-45](file://frontend/package.json#L1-L45) ## 性能考虑 - 数据库 @@ -338,8 +605,6 @@ PKGJSON --> NODE - 容器 - 后端与前端镜像体积较小,建议启用只读根文件系统与最小权限运行。 -(本节为通用指导,不直接分析具体文件) - ## 故障排查指南 - 健康检查 - 后端/CORS与健康检查端点可用于快速判断服务可用性。 @@ -352,14 +617,14 @@ PKGJSON --> NODE - 单元测试 - 认证模块测试覆盖注册、登录与当前用户接口,可作为回归测试基线。 -章节来源 -- [backend/app/main.py:45-48](file://backend/app/main.py#L45-L48) +**章节来源** +- [backend/app/main.py:97-100](file://backend/app/main.py#L97-L100) - [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150) - [backend/alembic/env.py:64-89](file://backend/alembic/env.py#L64-L89) - [tests/test_auth.py:1-104](file://tests/test_auth.py#L1-L104) ## 结论 -本部署与运维文档基于仓库现有配置,给出了从容器化到生产部署的实施路径与最佳实践建议。建议在生产环境中补充Nginx反向代理与SSL、集中化日志与监控、完善的备份与灾难恢复策略,并通过CI/CD实现自动化部署与回滚。 +本部署与运维文档基于仓库现有配置,给出了从容器化到生产部署的实施路径与最佳实践建议。建议在生产环境中补充Nginx反向代理与SSL、集中化日志与监控、完善的备份与灾难恢复策略,并通过CI/CD实现自动化部署与回滚。文档涵盖了Docker容器化部署、生产环境策略、监控日志管理、运维最佳实践和CI/CD流水线等关键内容,为GEO项目的稳定运行提供了全面的技术保障。 ## 附录 @@ -374,7 +639,7 @@ PKGJSON --> NODE - 数据库:localhost:5432 - Redis:localhost:6379 -章节来源 +**章节来源** - [docker-compose.yml:1-71](file://docker-compose.yml#L1-L71) ### B. 生产环境部署策略 @@ -385,8 +650,6 @@ PKGJSON --> NODE - 环境隔离 - 区分开发、测试、预发布与生产环境,严格管理环境变量与密钥。 -(本节为通用指导,不直接分析具体文件) - ### C. 监控与日志管理 - 健康检查 - 利用/CORS与健康检查端点,结合探针实现自动发现与告警。 @@ -395,8 +658,6 @@ PKGJSON --> NODE - 性能监控 - 关注数据库慢查询、Redis命中率、API响应时间与错误率。 -(本节为通用指导,不直接分析具体文件) - ### D. 运维最佳实践 - 备份策略 - 数据库与Redis定期快照与归档,验证恢复流程。 @@ -405,14 +666,10 @@ PKGJSON --> NODE - 故障恢复 - 制定回滚预案与演练计划,确保快速恢复。 -(本节为通用指导,不直接分析具体文件) - ### E. CI/CD流水线与自动化部署 - 建议阶段 - 代码提交触发测试(含认证接口测试),通过后构建镜像并推送制品库,随后部署到目标环境。 - 回滚机制 - 支持一键回滚至上一个稳定版本。 - 配置管理 - - 环境变量与密钥通过安全渠道注入,避免硬编码。 - -(本节为通用指导,不直接分析具体文件) \ No newline at end of file + - 环境变量与密钥通过安全渠道注入,避免硬编码。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/项目概述/核心功能/核心功能.md b/.qoder/repowiki/zh/content/项目概述/核心功能/核心功能.md index 48412cb..9ed3306 100644 --- a/.qoder/repowiki/zh/content/项目概述/核心功能/核心功能.md +++ b/.qoder/repowiki/zh/content/项目概述/核心功能/核心功能.md @@ -7,18 +7,48 @@ - [backend/app/api/queries.py](file://backend/app/api/queries.py) - [backend/app/api/citations.py](file://backend/app/api/citations.py) - [backend/app/api/reports.py](file://backend/app/api/reports.py) +- [backend/app/api/lifecycle.py](file://backend/app/api/lifecycle.py) +- [backend/app/api/knowledge.py](file://backend/app/api/knowledge.py) - [backend/app/services/auth.py](file://backend/app/services/auth.py) - [backend/app/services/query.py](file://backend/app/services/query.py) - [backend/app/services/citation.py](file://backend/app/services/citation.py) +- [backend/app/services/analytics/tracker.py](file://backend/app/services/analytics/tracker.py) +- [backend/app/services/analytics/insights.py](file://backend/app/services/analytics/insights.py) +- [backend/app/services/knowledge/rag_service.py](file://backend/app/services/knowledge/rag_service.py) +- [backend/app/agent_framework/agents/__init__.py](file://backend/app/agent_framework/agents/__init__.py) +- [backend/app/agent_framework/agents/citation_detector.py](file://backend/app/agent_framework/agents/citation_detector.py) +- [backend/app/agent_framework/agents/content_generator_agent.py](file://backend/app/agent_framework/agents/content_generator_agent.py) +- [backend/app/agent_framework/agents/deai_agent.py](file://backend/app/agent_framework/agents/deai_agent.py) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py](file://backend/app/agent_framework/agents/geo_optimizer_agent.py) +- [backend/app/agent_framework/pipeline/engine.py](file://backend/app/agent_framework/pipeline/engine.py) +- [backend/app/agent_framework/pipeline/loader.py](file://backend/app/agent_framework/pipeline/loader.py) +- [backend/app/agent_framework/dispatcher.py](file://backend/app/agent_framework/dispatcher.py) - [backend/app/models/query.py](file://backend/app/models/query.py) - [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py) -- [backend/app/workers/scheduler.py](file://backend/app/workers/scheduler.py) -- [backend/app/workers/citation_engine.py](file://backend/app/workers/citation_engine.py) -- [backend/app/workers/platforms/base.py](file://backend/app/workers/platforms/base.py) +- [backend/app/models/lifecycle.py](file://backend/app/models/lifecycle.py) +- [backend/app/models/knowledge.py](file://backend/app/models/knowledge.py) +- [backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py](file://backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py) +- [backend/workers/scheduler.py](file://backend/workers/scheduler.py) +- [backend/workers/citation_engine.py](file://backend/workers/citation_engine.py) +- [backend/workers/platforms/base.py](file://backend/workers/platforms/base.py) - [frontend/app/(dashboard)/dashboard/page.tsx](file://frontend/app/(dashboard)/dashboard/page.tsx) +- [frontend/app/(dashboard)/dashboard/admin/page.tsx](file://frontend/app/(dashboard)/dashboard/admin/page.tsx) +- [frontend/app/(dashboard)/dashboard/agents/page.tsx](file://frontend/app/(dashboard)/dashboard/agents/page.tsx) +- [frontend/app/(dashboard)/dashboard/analytics/page.tsx](file://frontend/app/(dashboard)/dashboard/analytics/page.tsx) +- [frontend/app/(dashboard)/dashboard/lifecycle/page.tsx](file://frontend/app/(dashboard)/dashboard/lifecycle/page.tsx) +- [frontend/app/(dashboard)/dashboard/knowledge/page.tsx](file://frontend/app/(dashboard)/dashboard/knowledge/page.tsx) - [frontend/components/charts/trend-chart.tsx](file://frontend/components/charts/trend-chart.tsx) +- [frontend/lib/api/lifecycle.ts](file://frontend/lib/api/lifecycle.ts) +## 更新摘要 +**变更内容** +- 新增AI代理框架模块,包含引用检测、内容生成、去AI化、GEO优化等智能代理 +- 新增业务生命周期管理系统,支持品牌项目全生命周期管理 +- 新增分析监控系统,提供发布追踪、效果分析和智能洞察生成功能 +- 新增知识库服务模块,支持RAG检索、文档管理和知识库CRUD操作 +- 扩展前端界面,新增代理管理、分析监控、生命周期管理和知识库管理页面 + ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) @@ -36,11 +66,15 @@ - 用户认证与权限管理:基于邮箱/密码注册登录、JWT 访问令牌签发与校验、会话保护接口。 - 智能查询任务管理:查询词创建、更新、删除、分页查询;按日/周/月频率自动调度;手动触发即时查询。 - 品牌引用检测引擎:多阶段匹配(精确/别名/模糊)、置信度评分、竞争品牌识别、上下文片段抽取。 -- 多 AI 平台数据集成:抽象适配器模式对接不同大模型平台,统一查询与结果处理。 +- 多AI平台数据集成:抽象适配器模式对接不同大模型平台,统一查询与结果处理。 +- AI代理框架:基于Pipeline的多代理协作系统,支持引用检测、内容生成、去AI化、GEO优化等智能任务编排。 +- 业务生命周期管理:品牌项目全生命周期管理,包含5个阶段的项目推进和状态跟踪。 +- 分析监控系统:发布效果追踪、内容表现分析、智能洞察生成和性能监控。 +- 知识库服务:RAG检索、文档管理、知识库CRUD操作和搜索日志记录。 - 数据分析与可视化:统计指标(总查询/引用次数、引用率、平均位置)、平台对比、30 天趋势折线图。 - 报告导出:CSV 导出引用记录,便于离线分析与归档。 -这些功能围绕“查询—检测—统计—可视—导出”的闭环展开,既满足管理员对系统运行与任务调度的掌控,也服务于研究人员对品牌监测与趋势分析的需求。 +这些功能围绕"查询—检测—智能代理—生命周期—分析监控—知识库—统计—可视—导出"的完整生态展开,既满足管理员对系统运行与任务调度的掌控,也服务于研究人员对品牌监测与趋势分析的需求。 ## 项目结构 后端采用 FastAPI + SQLAlchemy 异步 ORM,按领域划分 API、服务、模型与工作器;前端使用 Next.js + React,通过自定义 API 客户端与后端交互;数据库为 PostgreSQL。 @@ -49,21 +83,37 @@ graph TB subgraph "后端" A["FastAPI 应用
app/main.py"] -B["API 层
auth/queries/citations/reports"] -C["服务层
auth/query/citation"] -D["模型层
Query/CitationRecord"] +B["API 层
auth/queries/citations/reports/lifecycle/knowledge"] +C["服务层
auth/query/citation/analytics/knowledge"] +D["模型层
Query/CitationRecord/Lifecycle/Knowledge"] E["工作器
Scheduler/CitationEngine/Platforms"] +F["AI代理框架
Agents/Pipeline/Dispatcher"] +G["分析监控
Tracker/Insights"] +H["知识库服务
RAGService/Chunker/Embedder"] end subgraph "前端" -F["仪表盘页面
dashboard/page.tsx"] -G["趋势图表组件
trend-chart.tsx"] +I["仪表盘页面
dashboard/page.tsx"] +J["管理员页面
admin/page.tsx"] +K["代理管理页面
agents/page.tsx"] +L["分析监控页面
analytics/page.tsx"] +M["生命周期页面
lifecycle/page.tsx"] +N["知识库页面
knowledge/page.tsx"] +O["趋势图表组件
trend-chart.tsx"] end A --> B B --> C C --> D C --> E -F --> G -F --> B +C --> F +C --> G +C --> H +I --> O +I --> B +J --> B +K --> F +L --> G +M --> D +N --> H ``` **图表来源** @@ -72,14 +122,29 @@ F --> B - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) - [backend/app/api/citations.py:1-78](file://backend/app/api/citations.py#L1-L78) - [backend/app/api/reports.py:1-47](file://backend/app/api/reports.py#L1-L47) +- [backend/app/api/lifecycle.py:1-297](file://backend/app/api/lifecycle.py#L1-L297) +- [backend/app/api/knowledge.py:1-502](file://backend/app/api/knowledge.py#L1-L502) - [backend/app/services/auth.py:1-69](file://backend/app/services/auth.py#L1-L69) - [backend/app/services/query.py:1-130](file://backend/app/services/query.py#L1-L130) - [backend/app/services/citation.py:1-269](file://backend/app/services/citation.py#L1-L269) +- [backend/app/services/analytics/tracker.py:1-230](file://backend/app/services/analytics/tracker.py#L1-L230) +- [backend/app/services/analytics/insights.py:1-313](file://backend/app/services/analytics/insights.py#L1-L313) +- [backend/app/services/knowledge/rag_service.py:1-43](file://backend/app/services/knowledge/rag_service.py#L1-L43) +- [backend/app/agent_framework/agents/__init__.py:1-14](file://backend/app/agent_framework/agents/__init__.py#L1-L14) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) - [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55) - [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) -- [backend/app/workers/citation_engine.py:1-309](file://backend/app/workers/citation_engine.py#L1-L309) +- [backend/app/models/lifecycle.py:1-91](file://backend/app/models/lifecycle.py#L1-L91) +- [backend/app/models/knowledge.py:1-43](file://backend/app/models/knowledge.py#L1-L43) +- [backend/workers/scheduler.py:1-95](file://backend/workers/scheduler.py#L1-L95) +- [backend/workers/citation_engine.py:1-309](file://backend/workers/citation_engine.py#L1-L309) - [frontend/app/(dashboard)/dashboard/page.tsx:1-156](file://frontend/app/(dashboard)/dashboard/page.tsx#L1-L156) +- [frontend/app/(dashboard)/dashboard/admin/page.tsx:1-200](file://frontend/app/(dashboard)/dashboard/admin/page.tsx#L1-L200) +- [frontend/app/(dashboard)/dashboard/agents/page.tsx:1-200](file://frontend/app/(dashboard)/dashboard/agents/page.tsx#L1-L200) +- [frontend/app/(dashboard)/dashboard/analytics/page.tsx:1-200](file://frontend/app/(dashboard)/dashboard/analytics/page.tsx#L1-L200) +- [frontend/app/(dashboard)/dashboard/lifecycle/page.tsx:1-200](file://frontend/app/(dashboard)/dashboard/lifecycle/page.tsx#L1-L200) +- [frontend/app/(dashboard)/dashboard/knowledge/page.tsx:1-200](file://frontend/app/(dashboard)/dashboard/knowledge/page.tsx#L1-L200) - [frontend/components/charts/trend-chart.tsx:1-60](file://frontend/components/charts/trend-chart.tsx#L1-L60) **章节来源** @@ -88,7 +153,7 @@ F --> B ## 核心组件 - 认证与权限 - 注册/登录:邮箱唯一性校验、密码哈希、JWT 签发;当前用户信息读取。 - - 权限边界:所有业务接口均通过当前用户上下文进行资源归属校验(查询、引用、统计、导出)。 + - 权限边界:所有业务接口均通过当前用户上下文进行资源归属校验(查询、引用、统计、导出、生命周期、知识库)。 - 查询任务管理 - 查询 CRUD:分页列表、创建、读取、更新、删除;创建时校验用户配额上限;更新时可重算下次执行时间。 - 自动调度:每小时扫描到期查询,自动触发引用检测;手动触发即时查询。 @@ -97,7 +162,23 @@ F --> B - 竞争品牌:基于预设行业品牌库识别竞品。 - 结果持久化:生成引用记录,包含平台、是否引用、位置、文本、竞品集合、原始响应。 - 多 AI 平台集成 - - 适配器基类定义统一接口;内置“文心”“Kimi”适配器;未来可扩展更多平台。 + - 适配器基类定义统一接口;内置"文心""Kimi"适配器;未来可扩展更多平台。 +- AI代理框架 + - 代理实现:引用检测代理、内容生成代理、去AI化代理、GEO优化代理。 + - Pipeline编排:基于YAML的多阶段任务编排,支持变量解析、依赖管理、条件执行。 + - 任务分发:Redis队列驱动的任务分发器,支持任务状态跟踪和重试机制。 +- 业务生命周期管理 + - 项目管理:品牌基建、内容生产、AI适配优化、权威信号构建、持续运维5个阶段。 + - 状态跟踪:项目进度、阶段状态、完成率统计和时间轴事件记录。 + - 快速启动:一键创建项目并初始化5个阶段。 +- 分析监控系统 + - 发布追踪:内容发布记录、效果指标快照和平台分布统计。 + - 性能分析:内容表现排行、单篇内容深度分析和历史趋势追踪。 + - 智能洞察:基于LLM的自动化洞察生成和优化建议。 +- 知识库服务 + - RAG检索:文档分块、向量化嵌入和混合检索。 + - 文档管理:URL抓取、文本上传和分块预览。 + - 知识库CRUD:多租户知识库管理和搜索日志记录。 - 数据分析与可视化 - 统计聚合:总查询/引用数、引用率、平均位置、按平台汇总、30 天趋势。 - 前端展示:仪表盘卡片与趋势折线图组件。 @@ -113,12 +194,21 @@ F --> B - [backend/app/services/citation.py:1-269](file://backend/app/services/citation.py#L1-L269) - [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309) - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) +- [backend/app/agent_framework/agents/__init__.py:1-14](file://backend/app/agent_framework/agents/__init__.py#L1-L14) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) +- [backend/app/api/lifecycle.py:1-297](file://backend/app/api/lifecycle.py#L1-L297) +- [backend/app/models/lifecycle.py:1-91](file://backend/app/models/lifecycle.py#L1-L91) +- [backend/app/services/analytics/tracker.py:1-230](file://backend/app/services/analytics/tracker.py#L1-L230) +- [backend/app/services/analytics/insights.py:1-313](file://backend/app/services/analytics/insights.py#L1-L313) +- [backend/app/api/knowledge.py:1-502](file://backend/app/api/knowledge.py#L1-L502) +- [backend/app/services/knowledge/rag_service.py:1-43](file://backend/app/services/knowledge/rag_service.py#L1-L43) - [frontend/app/(dashboard)/dashboard/page.tsx:1-156](file://frontend/app/(dashboard)/dashboard/page.tsx#L1-L156) - [frontend/components/charts/trend-chart.tsx:1-60](file://frontend/components/charts/trend-chart.tsx#L1-L60) - [backend/app/api/reports.py:1-47](file://backend/app/api/reports.py#L1-L47) ## 架构总览 -下图展示从用户请求到数据落库与可视化的整体流程,以及定时调度与即时查询的协同机制。 +下图展示从用户请求到数据落库与可视化的整体流程,以及定时调度、智能代理编排、生命周期管理和分析监控的协同机制。 ```mermaid sequenceDiagram @@ -130,10 +220,12 @@ participant DB as "数据库" participant W as "工作器" participant CE as "引用检测引擎" participant P as "AI平台适配器" -U->>FE : 登录/访问仪表盘 -FE->>API : 获取统计/查询/引用/导出 +participant AG as "AI代理框架" +participant PL as "Pipeline引擎" +U->>FE : 登录/访问各功能页面 +FE->>API : 获取统计/查询/引用/导出/生命周期/知识库 API->>S : 参数校验与业务处理 -S->>DB : 读写查询/引用/任务 +S->>DB : 读写查询/引用/任务/项目/知识库 Note over S,DB : 权限校验:仅允许访问本人资源 API->>W : 触发/查询任务 W->>CE : 执行查询 @@ -141,6 +233,10 @@ CE->>P : 平台查询 P-->>CE : 原始响应 CE->>S : 写入引用记录 S->>DB : 持久化 +S->>AG : 分发代理任务 +AG->>PL : 执行Pipeline编排 +PL->>AG : 代理执行结果 +S->>DB : 更新代理状态 DB-->>S : 成功 S-->>API : 结果 API-->>FE : 响应数据/流式下载 @@ -149,9 +245,11 @@ API-->>FE : 响应数据/流式下载 **图表来源** - [backend/app/main.py:13-21](file://backend/app/main.py#L13-L21) - [backend/app/api/citations.py:59-77](file://backend/app/api/citations.py#L59-L77) -- [backend/app/workers/scheduler.py:51-84](file://backend/app/workers/scheduler.py#L51-L84) -- [backend/app/workers/citation_engine.py:159-234](file://backend/app/workers/citation_engine.py#L159-L234) +- [backend/app/workers/scheduler.py:51-84](file://backend/workers/scheduler.py#L51-L84) +- [backend/app/workers/citation_engine.py:159-234](file://backend/workers/citation_engine.py#L159-L234) - [backend/app/services/citation.py:204-234](file://backend/app/services/citation.py#L204-L234) +- [backend/app/agent_framework/dispatcher.py:54-117](file://backend/app/agent_framework/dispatcher.py#L54-L117) +- [backend/app/agent_framework/pipeline/engine.py:51-176](file://backend/app/agent_framework/pipeline/engine.py#L51-L176) ## 详细组件分析 @@ -202,7 +300,7 @@ API-->>U : {access_token,user} - 减少人工干预:按计划自动抓取与检测,提升研究效率。 - 灵活控制:支持日/周/月频率与手动触发,兼顾实时性与成本。 - 典型场景 - - 研究员创建查询(关键词、目标品牌、平台、频率),系统按时自动执行;也可随时“立即执行”。 + - 研究员创建查询(关键词、目标品牌、平台、频率),系统按时自动执行;也可随时"立即执行"。 ```mermaid flowchart TD @@ -220,13 +318,13 @@ UpdateTime --> Done(["完成一轮周期"]) **图表来源** - [backend/app/services/query.py:45-81](file://backend/app/services/query.py#L45-L81) -- [backend/app/workers/scheduler.py:51-84](file://backend/app/workers/scheduler.py#L51-L84) +- [backend/app/workers/scheduler.py:51-84](file://backend/workers/scheduler.py#L51-L84) - [backend/app/workers/citation_engine.py:291-300](file://backend/app/workers/citation_engine.py#L291-L300) **章节来源** - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) - [backend/app/services/query.py:1-130](file://backend/app/services/query.py#L1-L130) -- [backend/app/workers/scheduler.py:1-95](file://backend/app/workers/scheduler.py#L1-L95) +- [backend/app/workers/scheduler.py:1-95](file://backend/workers/scheduler.py#L1-L95) ### 品牌引用检测引擎 - 功能要点 @@ -237,7 +335,7 @@ UpdateTime --> Done(["完成一轮周期"]) - 置信度评分:帮助判断引用可靠性;模糊匹配提供兜底发现。 - 上下文定位:快速定位品牌在原文中的首次出现段落,便于人工复核。 - 典型场景 - - 文本中提及“XX品牌”,匹配器判定为“别名命中”,置信度0.9,并返回首次出现段落片段。 + - 文本中提及"XX品牌",匹配器判定为"别名命中",置信度0.9,并返回首次出现段落片段。 ```mermaid classDiagram @@ -272,12 +370,12 @@ CitationEngine --> BasePlatformAdapter : "委托查询" ### 多 AI 平台数据集成 - 功能要点 - 适配器基类定义统一接口(平台名、URL、查询方法)。 - - 内置“文心”“Kimi”适配器;引擎按查询配置的平台列表逐一执行。 + - 内置"文心""Kimi"适配器;引擎按查询配置的平台列表逐一执行。 - 核心价值 - 解耦平台差异:统一调用入口,便于扩展更多平台。 - 可观测性:每个平台独立任务状态(pending/running/success/failed)。 - 典型场景 - - 查询配置包含“wenxin,kimi”,引擎为两者分别创建任务并行执行,最终汇总结果。 + - 查询配置包含"wenxin,kimi",引擎为两者分别创建任务并行执行,最终汇总结果。 ```mermaid sequenceDiagram @@ -303,6 +401,204 @@ end - [backend/app/workers/platforms/base.py:1-18](file://backend/app/workers/platforms/base.py#L1-L18) - [backend/app/workers/citation_engine.py:151-157](file://backend/app/workers/citation_engine.py#L151-L157) +### AI代理框架 +- 功能要点 + - 代理实现:CitationDetectorAgent、ContentGeneratorAgent、DeAIAgent、GEOOptimizerAgent。 + - Pipeline编排:支持变量解析、依赖管理、条件执行、重试机制。 + - 任务分发:Redis队列驱动,支持任务状态跟踪、进度上报和回调机制。 +- 核心价值 + - 智能化编排:将复杂的多步骤任务分解为可组合的代理单元。 + - 可扩展性:新的代理类型可通过简单接口接入框架。 + - 可观测性:完整的任务生命周期跟踪和性能监控。 +- 典型场景 + - 内容生产Pipeline:主题选择 → 文章生成 → 去AI化 → GEO优化 → 发布。 + +```mermaid +classDiagram +class BaseAgent { +<> ++execute(task) TaskResult ++report_progress(task_id, progress, message) ++get_capabilities() AgentCapability +} +class CitationDetectorAgent { ++execute_full_detect(task) dict ++execute_single_detect(task) dict +} +class ContentGeneratorAgent { ++_generate_topics(task) dict ++_generate_article(task) dict +} +class DeAIAgent { ++_process(task) dict +} +class GEOOptimizerAgent { ++_optimize(task) dict +} +class PipelineEngine { ++execute(pipeline, context) PipelineResult ++_execute_stage(stage, ctx, stages_ctx) StageResult +} +class TaskDispatcher { ++dispatch(task, org_id, user_id) str ++get_task_status(task_id) dict ++handle_result(result) +} +BaseAgent <|-- CitationDetectorAgent +BaseAgent <|-- ContentGeneratorAgent +BaseAgent <|-- DeAIAgent +BaseAgent <|-- GEOOptimizerAgent +PipelineEngine --> BaseAgent : "编排执行" +TaskDispatcher --> BaseAgent : "任务分发" +``` + +**图表来源** +- [backend/app/agent_framework/agents/citation_detector.py:24-218](file://backend/app/agent_framework/agents/citation_detector.py#L24-L218) +- [backend/app/agent_framework/agents/content_generator_agent.py:23-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L23-L299) +- [backend/app/agent_framework/agents/deai_agent.py:21-156](file://backend/app/agent_framework/agents/deai_agent.py#L21-L156) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:23-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L23-L198) +- [backend/app/agent_framework/pipeline/engine.py:31-536](file://backend/app/agent_framework/pipeline/engine.py#L31-L536) +- [backend/app/agent_framework/dispatcher.py:32-367](file://backend/app/agent_framework/dispatcher.py#L32-L367) + +**章节来源** +- [backend/app/agent_framework/agents/__init__.py:1-14](file://backend/app/agent_framework/agents/__init__.py#L1-L14) +- [backend/app/agent_framework/agents/citation_detector.py:1-218](file://backend/app/agent_framework/agents/citation_detector.py#L1-L218) +- [backend/app/agent_framework/agents/content_generator_agent.py:1-299](file://backend/app/agent_framework/agents/content_generator_agent.py#L1-L299) +- [backend/app/agent_framework/agents/deai_agent.py:1-156](file://backend/app/agent_framework/agents/deai_agent.py#L1-L156) +- [backend/app/agent_framework/agents/geo_optimizer_agent.py:1-198](file://backend/app/agent_framework/agents/geo_optimizer_agent.py#L1-L198) +- [backend/app/agent_framework/pipeline/engine.py:1-536](file://backend/app/agent_framework/pipeline/engine.py#L1-L536) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) + +### 业务生命周期管理 +- 功能要点 + - 项目创建:快速启动功能,自动生成5个阶段的项目。 + - 阶段管理:品牌基建、内容生产、AI适配优化、权威信号构建、持续运维。 + - 状态跟踪:项目进度、阶段状态、完成率统计和时间轴事件记录。 + - 统计分析:组织级别的项目统计和阶段分布。 +- 核心价值 + - 全生命周期视角:从品牌建设到持续运营的完整流程管理。 + - 可视化跟踪:阶段进度卡片和时间轴展示项目进展。 + - 数据驱动决策:基于统计数据的项目管理和资源配置。 +- 典型场景 + - 管理员创建品牌项目 → 各阶段负责人推进 → 实时查看进度 → 生成项目报告。 + +```mermaid +sequenceDiagram +participant Admin as "管理员" +participant API as "生命周期API" +participant S as "生命周期服务" +participant DB as "数据库" +Admin->>API : POST /api/v1/lifecycle/projects/quick-start +API->>S : 创建项目和5个阶段 +S->>DB : 插入LifecycleProject和ProjectStage +DB-->>S : 成功 +S-->>API : 返回项目详情 +API-->>Admin : 项目创建成功 +Admin->>API : GET /api/v1/lifecycle/projects/{id}/timeline +API->>S : 获取时间轴事件 +S->>DB : 查询项目和阶段 +DB-->>S : 事件列表 +S-->>API : 时间轴数据 +API-->>Admin : 渲染时间轴 +``` + +**图表来源** +- [backend/app/api/lifecycle.py:190-230](file://backend/app/api/lifecycle.py#L190-L230) +- [backend/app/api/lifecycle.py:138-187](file://backend/app/api/lifecycle.py#L138-L187) +- [backend/app/models/lifecycle.py:12-91](file://backend/app/models/lifecycle.py#L12-L91) + +**章节来源** +- [backend/app/api/lifecycle.py:1-297](file://backend/app/api/lifecycle.py#L1-L297) +- [backend/app/models/lifecycle.py:1-91](file://backend/app/models/lifecycle.py#L1-L91) +- [frontend/lib/api/lifecycle.ts:53-95](file://frontend/lib/api/lifecycle.ts#L53-L95) + +### 分析监控系统 +- 功能要点 + - 发布追踪:记录内容发布事件、更新效果指标和生成快照。 + - 性能分析:内容表现排行、单篇内容深度分析和历史趋势。 + - 智能洞察:基于LLM的自动化洞察生成,包含趋势、异常、机会和建议。 + - 统计概览:组织级别的发布统计、平台分布和互动率分析。 +- 核心价值 + - 数据驱动优化:基于真实效果数据的自动化洞察和建议。 + - 全面监控:从发布到效果的全流程数据追踪。 + - 智能辅助:AI驱动的分析和优化建议,提升内容质量。 +- 典型场景 + - 内容发布后自动记录效果 → 定期生成洞察报告 → 基于建议优化内容策略。 + +```mermaid +sequenceDiagram +participant CMS as "内容管理系统" +participant API as "分析API" +participant S as "分析服务" +participant DB as "数据库" +CMS->>API : POST /api/v1/analytics/publish +API->>S : 记录发布事件 +S->>DB : 插入PublishRecord +DB-->>S : 成功 +S->>DB : 插入ContentMetrics快照 +CMS->>API : GET /api/v1/analytics/insights +API->>S : 生成洞察 +S->>S : 调用LLM分析数据 +S->>DB : 插入OptimizationInsight +DB-->>S : 成功 +S-->>API : 返回洞察结果 +API-->>CMS : 洞察报告 +``` + +**图表来源** +- [backend/app/services/analytics/tracker.py:16-51](file://backend/app/services/analytics/tracker.py#L16-L51) +- [backend/app/services/analytics/insights.py:40-103](file://backend/app/services/analytics/insights.py#L40-L103) +- [backend/app/services/analytics/tracker.py:53-128](file://backend/app/services/analytics/tracker.py#L53-L128) + +**章节来源** +- [backend/app/services/analytics/tracker.py:1-230](file://backend/app/services/analytics/tracker.py#L1-L230) +- [backend/app/services/analytics/insights.py:1-313](file://backend/app/services/analytics/insights.py#L1-L313) + +### 知识库服务 +- 功能要点 + - RAG检索:文档分块、向量化嵌入和混合检索,支持多知识库查询。 + - 文档管理:支持URL抓取和文本上传,自动计算内容哈希和分块数量。 + - 知识库CRUD:多租户知识库管理,支持文档级联删除和统计更新。 + - 搜索日志:记录搜索查询、结果数量和延迟时间。 +- 核心价值 + - 智能检索:基于向量和关键词的混合检索,提升相关性。 + - 知识管理:结构化的知识库管理和版本控制。 + - 效率提升:自动化的文档处理和检索,减少人工维护成本。 +- 典型场景 + - 研究员上传行业报告 → 系统自动分块嵌入 → 搜索相关知识 → 生成内容。 + +```mermaid +sequenceDiagram +participant User as "用户" +participant API as "知识库API" +participant S as "RAG服务" +participant DB as "数据库" +User->>API : POST /api/v1/knowledge/bases/{kb_id}/documents +API->>S : 上传文档 +S->>DB : 插入KnowledgeDocument +S->>S : 分块 → 向量化 → 存储 +S->>DB : 插入KnowledgeChunk +DB-->>S : 成功 +S-->>API : 返回文档详情 +API-->>User : 上传完成 +User->>API : POST /api/v1/knowledge/search +API->>S : 执行RAG检索 +S->>DB : 查询向量相似度 +DB-->>S : 相关文档 +S-->>API : 返回检索结果 +API-->>User : 检索结果 +``` + +**图表来源** +- [backend/app/api/knowledge.py:217-293](file://backend/app/api/knowledge.py#L217-L293) +- [backend/app/api/knowledge.py:424-501](file://backend/app/api/knowledge.py#L424-L501) +- [backend/app/services/knowledge/rag_service.py:33-43](file://backend/app/services/knowledge/rag_service.py#L33-L43) + +**章节来源** +- [backend/app/api/knowledge.py:1-502](file://backend/app/api/knowledge.py#L1-L502) +- [backend/app/services/knowledge/rag_service.py:1-43](file://backend/app/services/knowledge/rag_service.py#L1-L43) +- [backend/app/models/knowledge.py:1-43](file://backend/app/models/knowledge.py#L1-L43) + ### 数据分析与可视化 - 功能要点 - 统计接口:总查询/引用数、引用率、平均位置、按平台汇总、30 天趋势(按自然周聚合)。 @@ -311,7 +607,7 @@ end - 快速洞察:总览指标帮助评估监测效果与变化趋势。 - 易用性:图表直观呈现,降低阅读成本。 - 典型场景 - - 研究人员查看“过去30天引用趋势”,发现某周显著上升,结合上下文进一步分析。 + - 研究人员查看"过去30天引用趋势",发现某周显著上升,结合上下文进一步分析。 ```mermaid sequenceDiagram @@ -377,43 +673,65 @@ API-->>FE : 流式响应(Attachment) - API 层仅负责参数解析与鉴权,业务逻辑集中在服务层,降低控制器复杂度。 - 引擎与平台适配器通过抽象接口解耦,便于替换与扩展。 - 调度器与引擎通过 ORM 与任务表协作,避免直接耦合业务数据。 + - AI代理框架通过任务分发器与代理实现松耦合。 + - 生命周期管理与项目阶段通过外键关联,确保数据一致性。 - 外部依赖 - FastAPI/SQLAlchemy:Web 框架与 ORM。 - APScheduler:异步定时任务调度。 - Recharts:前端图表渲染。 + - Redis:异步任务队列和缓存。 + - LLM提供商:OpenAI、DeepSeek等大模型服务。 - 潜在风险 - 平台适配器异常需隔离,避免影响其他平台任务。 - 大量并发查询可能带来数据库与外部平台压力,建议限流与重试策略。 + - AI代理任务的LLM调用可能存在成本控制和速率限制问题。 ```mermaid graph LR API["API层"] --> SVC["服务层"] SVC --> MODEL["模型层"] SVC --> WORKER["工作器"] +SVC --> AGENT["AI代理框架"] +SVC --> ANALYTICS["分析监控"] +SVC --> KNOWLEDGE["知识库服务"] WORKER --> ADAPTER["平台适配器"] +AGENT --> DISPATCHER["任务分发器"] +ANALYTICS --> LLM["LLM提供商"] +KNOWLEDGE --> VECTOR["向量数据库"] FE["前端"] --> API ``` **图表来源** - [backend/app/main.py:38-42](file://backend/app/main.py#L38-L42) - [backend/app/workers/citation_engine.py:151-157](file://backend/app/workers/citation_engine.py#L151-L157) +- [backend/app/agent_framework/dispatcher.py:35-46](file://backend/app/agent_framework/dispatcher.py#L35-L46) **章节来源** - [backend/app/main.py:1-48](file://backend/app/main.py#L1-L48) - [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309) +- [backend/app/agent_framework/dispatcher.py:1-367](file://backend/app/agent_framework/dispatcher.py#L1-L367) ## 性能考虑 - 数据库 - 查询索引:查询与引用记录表均建立常用过滤字段索引,减少扫描开销。 - 分页与聚合:统计接口使用分组与聚合,避免一次性拉取全量数据。 + - 连接池:合理配置数据库连接池大小,避免连接争用。 - 引擎与平台 - 并行执行:同一查询的不同平台可并行处理,缩短总耗时。 - 错误隔离:单平台失败不影响其他平台,保证整体可用性。 + - 缓存策略:对频繁查询的结果进行缓存,减少重复计算。 - 前端 - 图表懒加载与响应式容器,提升大屏体验。 - 导出采用流式响应,避免内存峰值。 - -[本节为通用指导,无需具体文件分析] + - 代理状态轮询优化,避免过度请求。 +- AI代理框架 + - 任务队列:Redis队列支持高并发任务处理。 + - 超时控制:为LLM调用设置合理的超时时间。 + - 重试机制:失败任务自动重试,支持指数退避。 +- 知识库服务 + - 向量索引:优化向量相似度查询性能。 + - 分块策略:合理设置分块大小,平衡精度与性能。 + - 批量处理:批量插入和更新操作,减少数据库往返。 ## 故障排查指南 - 认证问题 @@ -421,8 +739,24 @@ FE["前端"] --> API - 登录失败:邮箱或密码错误;确认凭据正确与网络可达。 - 查询任务 - 创建被拒:超出配额;联系管理员提升限额或清理历史查询。 - - 无法执行:查询状态非“active”或未配置平台;检查状态与平台列表。 + - 无法执行:查询状态非"active"或未配置平台;检查状态与平台列表。 - 即时查询无响应:平台适配器异常或网络超时;查看任务状态与错误信息。 +- AI代理框架 + - 代理任务失败:检查代理配置、LLM提供商连接和任务输入参数。 + - Pipeline执行错误:验证YAML语法、依赖关系和变量引用。 + - 任务超时:调整超时设置或优化LLM调用参数。 +- 生命周期管理 + - 项目创建失败:检查组织权限和品牌名称唯一性。 + - 阶段推进异常:确认阶段状态和前置条件满足。 + - 统计数据缺失:验证项目数据完整性和时间范围设置。 +- 分析监控 + - 发布记录丢失:检查发布事件记录和数据库连接。 + - 洞察生成失败:确认LLM提供商可用性和API密钥配置。 + - 性能数据异常:验证指标计算逻辑和数据完整性。 +- 知识库服务 + - 文档上传失败:检查文件大小限制和内容格式。 + - 检索结果不准确:验证向量嵌入质量和检索参数设置。 + - 搜索日志缺失:确认日志记录和数据库写入权限。 - 统计与导出 - 统计为空:可能因筛选条件导致无数据;尝试放宽时间范围或移除查询筛选。 - 导出失败:查询不存在或无权限;确认 query_id 与登录态。 @@ -435,21 +769,27 @@ FE["前端"] --> API - [backend/app/services/citation.py:204-234](file://backend/app/services/citation.py#L204-L234) - [backend/app/api/reports.py:16-46](file://backend/app/api/reports.py#L16-L46) - [backend/app/workers/scheduler.py:30-40](file://backend/app/workers/scheduler.py#L30-L40) +- [backend/app/agent_framework/dispatcher.py:118-154](file://backend/app/agent_framework/dispatcher.py#L118-L154) +- [backend/app/api/lifecycle.py:190-230](file://backend/app/api/lifecycle.py#L190-L230) +- [backend/app/services/analytics/tracker.py:16-51](file://backend/app/services/analytics/tracker.py#L16-L51) +- [backend/app/api/knowledge.py:217-293](file://backend/app/api/knowledge.py#L217-L293) ## 结论 -GEO 平台以“查询—检测—统计—可视—导出”为主线,构建了从自动化采集到深度分析的完整链路。通过严格的权限控制、可扩展的平台适配器、稳健的定时调度与清晰的可视化输出,既能满足管理员对系统运行的掌控,也能为研究人员提供高效、可靠的品牌监测工具。建议后续在平台适配器层面引入重试与熔断、在数据库侧增加慢查询监控与索引优化,持续提升稳定性与性能。 - -[本节为总结性内容,无需具体文件分析] +GEO 平台以"查询—检测—智能代理—生命周期—分析监控—知识库—统计—可视—导出"为主线,构建了从自动化采集到深度分析的完整链路。通过严格的权限控制、可扩展的平台适配器、稳健的定时调度、智能化的AI代理编排、全生命周期的项目管理和全面的分析监控体系,既能满足管理员对系统运行的掌控,也能为研究人员提供高效、可靠的品牌监测工具。新增的AI代理框架、业务生命周期管理、分析监控系统和知识库服务等核心功能模块,进一步增强了平台的智能化水平和业务服务能力。建议后续在代理任务的成本控制、生命周期管理的自动化程度、分析洞察的准确性以及知识库的规模扩展等方面持续优化,以提升整体用户体验和平台价值。 ## 附录 - 典型使用流程(管理员) - - 新建用户/分配配额 → 配置平台密钥 → 监控调度器运行 → 查看任务状态与错误日志 → 调整频率策略。 + - 新建用户/分配配额 → 配置平台密钥 → 监控调度器运行 → 查看任务状态与错误日志 → 调整频率策略 → 管理代理任务 → 监控分析数据 → 维护知识库内容。 - 典型使用流程(研究人员) - - 登录 → 创建查询(关键词/目标品牌/平台/频率) → 查看仪表盘趋势 → 导出报告 → 深度分析与汇报。 + - 登录 → 创建查询(关键词/目标品牌/平台/频率) → 查看仪表盘趋势 → 导出报告 → 使用知识库检索相关信息 → 生成内容并进行优化 → 发布内容并跟踪效果。 +- 典型使用流程(项目经理) + - 登录 → 快速启动品牌项目 → 分配各阶段任务 → 跟踪项目进度 → 查看阶段报告 → 管理团队成员 → 生成项目总结。 - 关键接口路径参考 - 认证:POST /api/v1/auth/register, POST /api/v1/auth/login, GET /api/v1/auth/me - 查询:GET/POST/GET/PATCH/DELETE /api/v1/queries - 引用:GET /api/v1/citations, GET /api/v1/citations/stats, POST /api/v1/queries/{query_id}/run-now - 报告:GET /api/v1/reports/export/csv - -[本节为概览性内容,无需具体文件分析] \ No newline at end of file + - 生命周期:POST /api/v1/lifecycle/projects/quick-start, GET /api/v1/lifecycle/projects/{id}/timeline + - 知识库:POST /api/v1/knowledge/bases, POST /api/v1/knowledge/bases/{kb_id}/documents, POST /api/v1/knowledge/search + - 分析监控:POST /api/v1/analytics/publish, GET /api/v1/analytics/insights + - AI代理:POST /api/v1/agents/{agent_name}/{task_type} \ No newline at end of file diff --git a/.qoder/repowiki/zh/meta/repowiki-metadata.json b/.qoder/repowiki/zh/meta/repowiki-metadata.json index d5b88d2..d9ccc89 100644 --- a/.qoder/repowiki/zh/meta/repowiki-metadata.json +++ b/.qoder/repowiki/zh/meta/repowiki-metadata.json @@ -1 +1 @@ -{"code_snippets":[{"id":"8a466b0c6eac2ccb54c5da7e13854646","path":"frontend/app/layout.tsx","line_range":"1-37","gmt_create":"2026-04-23T15:19:43.759937+08:00","gmt_modified":"2026-04-23T15:19:43.759937+08:00"},{"id":"3bd4eedea376e3a3d9f9fbff4fe27a65","path":"frontend/components/layout/sidebar.tsx","line_range":"1-54","gmt_create":"2026-04-23T15:19:43.760535+08:00","gmt_modified":"2026-04-23T15:19:43.760535+08:00"},{"id":"0d903468b55bdc63cc7e25a87a89c522","path":"frontend/components/layout/header.tsx","line_range":"1-30","gmt_create":"2026-04-23T15:19:43.760868+08:00","gmt_modified":"2026-04-23T15:19:43.760868+08:00"},{"id":"3bab92a09e9fb456e0303bb1e04afc7e","path":"frontend/components/ui/table.tsx","line_range":"1-118","gmt_create":"2026-04-23T15:19:43.762327+08:00","gmt_modified":"2026-04-23T15:19:43.762327+08:00"},{"id":"0eed9f61572209dd754611fc7c690d5a","path":"frontend/components/ui/dialog.tsx","line_range":"1-123","gmt_create":"2026-04-23T15:19:43.762637+08:00","gmt_modified":"2026-04-23T15:19:43.762637+08:00"},{"id":"b7796fc6197ecce5beb461b9466e54a0","path":"frontend/components/charts/trend-chart.tsx","line_range":"1-60","gmt_create":"2026-04-23T15:19:43.762953+08:00","gmt_modified":"2026-04-23T15:19:43.762953+08:00"},{"id":"6b9f52af0b6d78c17ff9bbc42d760ea2","path":"frontend/components/charts/platform-chart.tsx","line_range":"1-68","gmt_create":"2026-04-23T15:19:43.763292+08:00","gmt_modified":"2026-04-23T15:19:43.763292+08:00"},{"id":"a829403082cc3460c01e0110229c53c4","path":"frontend/lib/platforms.ts","line_range":"1-18","gmt_create":"2026-04-23T15:19:43.763596+08:00","gmt_modified":"2026-04-23T15:19:43.763596+08:00"},{"id":"dcfa308ef4ec368c5a51a17acbfc8e2c","path":"frontend/lib/utils.ts","line_range":"1-7","gmt_create":"2026-04-23T15:19:43.763899+08:00","gmt_modified":"2026-04-23T15:19:43.763899+08:00"},{"id":"0f87c8089f548883d056f0a0d79e273f","path":"frontend/lib/api.ts","line_range":"1-79","gmt_create":"2026-04-23T15:19:43.764207+08:00","gmt_modified":"2026-04-23T15:19:43.764207+08:00"},{"id":"9beee1f41fe8f0750fd97155f9d54bbb","path":"frontend/lib/api.ts","line_range":"67-70","gmt_create":"2026-04-23T15:19:43.7681+08:00","gmt_modified":"2026-04-23T15:19:43.7681+08:00"},{"id":"8fe2e22a963442076e1ce16ab777573c","path":"frontend/lib/api.ts","line_range":"56-66","gmt_create":"2026-04-23T15:19:43.769967+08:00","gmt_modified":"2026-04-23T15:19:43.769967+08:00"},{"id":"3124ad882ca2cf8fecb6b93696c7f233","path":"frontend/lib/api.ts","line_range":"72-77","gmt_create":"2026-04-23T15:19:43.77323+08:00","gmt_modified":"2026-04-23T15:19:43.773231+08:00"},{"id":"17a97b4ac37fb67b8eda7ce2887c38e7","path":"frontend/app/layout.tsx","line_range":"17-20","gmt_create":"2026-04-23T15:19:43.777372+08:00","gmt_modified":"2026-04-23T15:19:43.777372+08:00"},{"id":"84cba1e0d516e8c9859402fd5c1bc83c","path":"frontend/lib/api.ts","line_range":"3-40","gmt_create":"2026-04-23T15:19:43.777696+08:00","gmt_modified":"2026-04-23T15:19:43.777696+08:00"},{"id":"b55a164add5a8fec2ef0e489f7234829","path":"backend/app/main.py","line_range":"24-47","gmt_create":"2026-04-23T15:19:45.591156+08:00","gmt_modified":"2026-04-23T15:19:45.591157+08:00"},{"id":"fa1ee5e3822128a37e9d03af74083392","path":"backend/app/api/queries.py","line_range":"12","gmt_create":"2026-04-23T15:19:45.591868+08:00","gmt_modified":"2026-04-23T15:19:45.591868+08:00"},{"id":"7e908f05baccdfcf7f4a3ef3c9cd5c38","path":"backend/app/api/citations.py","line_range":"21","gmt_create":"2026-04-23T15:19:45.592191+08:00","gmt_modified":"2026-04-23T15:19:45.592191+08:00"},{"id":"ae9de874df4a46f4197b6c157c25ec6e","path":"backend/app/api/queries.py","line_range":"15-85","gmt_create":"2026-04-23T15:19:45.594458+08:00","gmt_modified":"2026-04-23T15:19:45.594458+08:00"},{"id":"c066a8d4bffabed87a2e38ccad81c107","path":"backend/app/api/citations.py","line_range":"25-77","gmt_create":"2026-04-23T15:19:45.594783+08:00","gmt_modified":"2026-04-23T15:19:45.594783+08:00"},{"id":"bcdf50f6234651cb9863ab210e6473e5","path":"backend/app/api/deps.py","line_range":"16-42","gmt_create":"2026-04-23T15:19:45.595733+08:00","gmt_modified":"2026-04-23T15:19:45.595733+08:00"},{"id":"6df0277c2486b148fa26c2682dbdaa4c","path":"backend/app/services/auth.py","line_range":"37-68","gmt_create":"2026-04-23T15:19:45.59605+08:00","gmt_modified":"2026-04-23T15:19:45.59605+08:00"},{"id":"5ea5f192d580031ffe57e1582b70c67e","path":"backend/app/services/query.py","line_range":"12-123","gmt_create":"2026-04-23T15:19:45.596359+08:00","gmt_modified":"2026-04-23T15:19:45.596359+08:00"},{"id":"fe4a793f16cd4e12b56253c0a6d53ae0","path":"backend/app/services/citation.py","line_range":"24-359","gmt_create":"2026-04-23T15:19:45.596722+08:00","gmt_modified":"2026-04-23T15:19:45.596723+08:00"},{"id":"4aad38dfc00a0877bd965c3d0b3c280c","path":"backend/app/schemas/auth.py","line_range":"7-34","gmt_create":"2026-04-23T15:19:45.598915+08:00","gmt_modified":"2026-04-23T15:19:45.598915+08:00"},{"id":"9b10dac7dbbb1327afc8a525bf4bd0c3","path":"backend/app/services/query.py","line_range":"45-81","gmt_create":"2026-04-23T15:19:45.599689+08:00","gmt_modified":"2026-04-23T15:19:45.599689+08:00"},{"id":"69118807690ef351a9de910414d5e676","path":"backend/app/schemas/query.py","line_range":"11-94","gmt_create":"2026-04-23T15:19:45.6004+08:00","gmt_modified":"2026-04-23T15:19:45.6004+08:00"},{"id":"212d822d207a4c0bd7825bbf20e188e9","path":"backend/app/api/citations.py","line_range":"59-77","gmt_create":"2026-04-23T15:19:45.601069+08:00","gmt_modified":"2026-04-23T15:19:45.601069+08:00"},{"id":"b0777c7da17be89abb333c81c0dcf349","path":"backend/app/services/citation.py","line_range":"204-261","gmt_create":"2026-04-23T15:19:45.601383+08:00","gmt_modified":"2026-04-23T15:19:45.601384+08:00"},{"id":"26288877e8e1f6c4ff5aca12610b0218","path":"backend/app/schemas/citation.py","line_range":"7-50","gmt_create":"2026-04-23T15:19:45.602042+08:00","gmt_modified":"2026-04-23T15:19:45.602042+08:00"},{"id":"56e46969bdb790a5e8f333184b878d6d","path":"backend/app/models/user.py","line_range":"11-41","gmt_create":"2026-04-23T15:19:45.605045+08:00","gmt_modified":"2026-04-23T15:19:45.605046+08:00"},{"id":"4fb8856be3a581fe8303d11b2284ca29","path":"backend/app/models/query.py","line_range":"11-55","gmt_create":"2026-04-23T15:19:45.605965+08:00","gmt_modified":"2026-04-23T15:19:45.605965+08:00"},{"id":"fd541971cebf8a7c167d717f5c5d1ff6","path":"backend/app/models/citation_record.py","line_range":"11-42","gmt_create":"2026-04-23T15:19:45.606627+08:00","gmt_modified":"2026-04-23T15:19:45.606627+08:00"},{"id":"b84f46f058847733347974841f613688","path":"backend/app/models/query_task.py","line_range":"11-39","gmt_create":"2026-04-23T15:19:45.607023+08:00","gmt_modified":"2026-04-23T15:19:45.607023+08:00"},{"id":"1a2657244414b5681afded9565a86422","path":"backend/app/models/user.py","line_range":"35-40","gmt_create":"2026-04-23T15:19:45.60817+08:00","gmt_modified":"2026-04-23T15:19:45.60817+08:00"},{"id":"acd5a29be2bdd4ae251e10ca266ffe13","path":"backend/app/models/query.py","line_range":"43-48","gmt_create":"2026-04-23T15:19:45.608565+08:00","gmt_modified":"2026-04-23T15:19:45.608565+08:00"},{"id":"27a5e2dd1d197b2e3a45be41c57a6183","path":"backend/app/models/citation_record.py","line_range":"35","gmt_create":"2026-04-23T15:19:45.609141+08:00","gmt_modified":"2026-04-23T15:19:45.609141+08:00"},{"id":"c43e8fc0c04c5ed2db7798d99c8c77b8","path":"backend/app/models/query_task.py","line_range":"34","gmt_create":"2026-04-23T15:19:45.609534+08:00","gmt_modified":"2026-04-23T15:19:45.609534+08:00"},{"id":"a50f983ec39bac67dff5df80f6dad837","path":"backend/app/services/query.py","line_range":"59-60","gmt_create":"2026-04-23T15:19:45.61019+08:00","gmt_modified":"2026-04-23T15:19:45.61019+08:00"},{"id":"55f1628f1ab6f323710e367e12146b1a","path":"backend/app/api/citations.py","line_range":"67-71","gmt_create":"2026-04-23T15:19:45.610496+08:00","gmt_modified":"2026-04-23T15:19:45.610496+08:00"},{"id":"096856da621e23e78422a15e2bfce1f1","path":"backend/app/main.py","line_range":"13-22","gmt_create":"2026-04-23T15:20:08.95664+08:00","gmt_modified":"2026-04-23T15:20:08.95664+08:00"},{"id":"e230904202fcf7a861c6f49b84f9f863","path":"backend/app/workers/scheduler.py","line_range":"25-95","gmt_create":"2026-04-23T15:20:08.956979+08:00","gmt_modified":"2026-04-23T15:20:08.956979+08:00"},{"id":"309607c54b12a6340edc086ffb4737c9","path":"backend/app/workers/citation_engine.py","line_range":"148-309","gmt_create":"2026-04-23T15:20:08.957311+08:00","gmt_modified":"2026-04-23T15:20:08.957311+08:00"},{"id":"d7c319a04abbc6704da53107e07dd8e7","path":"backend/app/services/query.py","line_range":"12-130","gmt_create":"2026-04-23T15:20:08.958773+08:00","gmt_modified":"2026-04-23T15:20:08.958773+08:00"},{"id":"9bfc041fe426da2eb78353827e8d9163","path":"backend/app/database.py","line_range":"1-29","gmt_create":"2026-04-23T15:20:08.95909+08:00","gmt_modified":"2026-04-23T15:20:08.95909+08:00"},{"id":"ad67863041d9eea2b0fb542b5aa33aca","path":"backend/app/workers/platforms/base.py","line_range":"4-18","gmt_create":"2026-04-23T15:20:08.959413+08:00","gmt_modified":"2026-04-23T15:20:08.959413+08:00"},{"id":"eecf9581dbaa0a515cf11514175e7ef9","path":"backend/app/workers/platforms/kimi.py","line_range":"11-206","gmt_create":"2026-04-23T15:20:08.959726+08:00","gmt_modified":"2026-04-23T15:20:08.959726+08:00"},{"id":"5563c29185326a59be61ee0a6eec4463","path":"backend/app/workers/platforms/wenxin.py","line_range":"11-205","gmt_create":"2026-04-23T15:20:08.960155+08:00","gmt_modified":"2026-04-23T15:20:08.960155+08:00"},{"id":"2d35e1345d25020f8e7ac1318db06f7b","path":"backend/app/workers/scheduler.py","line_range":"30-90","gmt_create":"2026-04-23T15:20:08.96886+08:00","gmt_modified":"2026-04-23T15:20:08.968861+08:00"},{"id":"91bda120c0ab69e0e7103a1c89c82424","path":"backend/app/workers/scheduler.py","line_range":"95-172","gmt_create":"2026-04-23T15:20:08.969219+08:00","gmt_modified":"2026-04-23T15:20:08.969219+08:00"},{"id":"160b5326537d25444c40a459a01e79c6","path":"backend/app/workers/citation_engine.py","line_range":"159-234","gmt_create":"2026-04-23T15:20:08.969565+08:00","gmt_modified":"2026-04-23T15:20:08.969565+08:00"},{"id":"6712051c987e10a7c26b089063367398","path":"backend/app/models/query.py","line_range":"24-31","gmt_create":"2026-04-23T15:20:08.970051+08:00","gmt_modified":"2026-04-23T15:20:08.970052+08:00"},{"id":"ac5982063da5f04315f3e82a0d653902","path":"backend/app/models/query_task.py","line_range":"24-32","gmt_create":"2026-04-23T15:20:08.970717+08:00","gmt_modified":"2026-04-23T15:20:08.970717+08:00"},{"id":"06ed912983db33bb8aca162fed68282b","path":"backend/app/models/citation_record.py","line_range":"24-29","gmt_create":"2026-04-23T15:20:08.971135+08:00","gmt_modified":"2026-04-23T15:20:08.971135+08:00"},{"id":"b624be78e3bffd876e403cff2557b088","path":"backend/app/workers/citation_engine.py","line_range":"19-120","gmt_create":"2026-04-23T15:20:08.973448+08:00","gmt_modified":"2026-04-23T15:20:08.973448+08:00"},{"id":"40d0b169aad65c8bb38077deb052fc72","path":"backend/app/workers/platforms/kimi.py","line_range":"33-125","gmt_create":"2026-04-23T15:20:08.97414+08:00","gmt_modified":"2026-04-23T15:20:08.97414+08:00"},{"id":"8b5af998852596e1e08b0e0216bc4b93","path":"backend/app/workers/platforms/wenxin.py","line_range":"33-124","gmt_create":"2026-04-23T15:20:08.974449+08:00","gmt_modified":"2026-04-23T15:20:08.974449+08:00"},{"id":"fe70b1fef9f36e73d26d84987e927c7a","path":"backend/app/api/queries.py","line_range":"15-86","gmt_create":"2026-04-23T15:20:08.978743+08:00","gmt_modified":"2026-04-23T15:20:08.978743+08:00"},{"id":"e1d2b027678118df4d0a50ce9269271d","path":"backend/app/workers/scheduler.py","line_range":"42-90","gmt_create":"2026-04-23T15:20:08.982815+08:00","gmt_modified":"2026-04-23T15:20:08.982815+08:00"},{"id":"e79301a4bc26aa6b49f3f52c3182c3f9","path":"backend/app/workers/citation_engine.py","line_range":"175-234","gmt_create":"2026-04-23T15:20:08.983609+08:00","gmt_modified":"2026-04-23T15:20:08.983609+08:00"},{"id":"1e85186eded8743ff5f231df4aa6df3f","path":"backend/app/workers/platforms/kimi.py","line_range":"21-48","gmt_create":"2026-04-23T15:20:08.98454+08:00","gmt_modified":"2026-04-23T15:20:08.98454+08:00"},{"id":"e2b1718570fb714b2f4342221898ab30","path":"backend/app/workers/platforms/wenxin.py","line_range":"21-48","gmt_create":"2026-04-23T15:20:08.985237+08:00","gmt_modified":"2026-04-23T15:20:08.985237+08:00"},{"id":"e4a49039dae40b7433896c81737fcf8c","path":"backend/app/config.py","line_range":"7-14","gmt_create":"2026-04-23T15:20:08.985763+08:00","gmt_modified":"2026-04-23T15:20:08.985763+08:00"},{"id":"2ee31d68c409e96e951f6cfa7027bca7","path":"backend/app/main.py","line_range":"24-42","gmt_create":"2026-04-23T15:20:08.986265+08:00","gmt_modified":"2026-04-23T15:20:08.986265+08:00"},{"id":"79d6e169e36e6b7493898b5f863e07dc","path":"backend/app/workers/citation_engine.py","line_range":"152-157","gmt_create":"2026-04-23T15:20:08.987693+08:00","gmt_modified":"2026-04-23T15:20:08.987693+08:00"},{"id":"1552315d5fb9f6d7aba5f7e8fa93a975","path":"backend/app/database.py","line_range":"6-10","gmt_create":"2026-04-23T15:20:08.988709+08:00","gmt_modified":"2026-04-23T15:20:08.988709+08:00"},{"id":"599cca7536cae4a7e0ae93043c476a7f","path":"tests/test_queries.py","line_range":"10-154","gmt_create":"2026-04-23T15:20:08.989011+08:00","gmt_modified":"2026-04-23T15:20:08.989011+08:00"},{"id":"2ec3d45edd6221e0cedf7f8887fe090d","path":"tests/test_scheduler.py","line_range":"17-123","gmt_create":"2026-04-23T15:20:08.989312+08:00","gmt_modified":"2026-04-23T15:20:08.989312+08:00"},{"id":"4d323bf0aaf4078f09726dc0890e5955","path":"backend/app/models/subscription.py","line_range":"11-37","gmt_create":"2026-04-23T15:21:46.688165+08:00","gmt_modified":"2026-04-23T15:21:46.688166+08:00"},{"id":"4cef9e740b6feb68c6bd22b660c47320","path":"backend/app/services/query.py","line_range":"1-123","gmt_create":"2026-04-23T15:21:46.688903+08:00","gmt_modified":"2026-04-23T15:21:46.688903+08:00"},{"id":"121203f7f9f539ffb1456c3f5cdfd842","path":"backend/app/services/citation.py","line_range":"1-359","gmt_create":"2026-04-23T15:21:46.689338+08:00","gmt_modified":"2026-04-23T15:21:46.689338+08:00"},{"id":"10d1e37bdc9f353c189b7a2fe79dc85e","path":"backend/app/api/queries.py","line_range":"1-86","gmt_create":"2026-04-23T15:21:46.689691+08:00","gmt_modified":"2026-04-23T15:21:46.689691+08:00"},{"id":"cbd0101fa84d957bcb1baaa623c6b31c","path":"backend/app/api/citations.py","line_range":"1-78","gmt_create":"2026-04-23T15:21:46.690036+08:00","gmt_modified":"2026-04-23T15:21:46.690036+08:00"},{"id":"afe4138895492c26aac5c0120ef46cd8","path":"backend/app/models/__init__.py","line_range":"1-14","gmt_create":"2026-04-23T15:21:46.69035+08:00","gmt_modified":"2026-04-23T15:21:46.69035+08:00"},{"id":"4d11ddf7abb8076d81b30c4315786f9a","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"21-128","gmt_create":"2026-04-23T15:21:46.693035+08:00","gmt_modified":"2026-04-23T15:21:46.693035+08:00"},{"id":"e454b4a54500bd81e7599e6ec97bf12b","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"23-37","gmt_create":"2026-04-23T15:21:46.695671+08:00","gmt_modified":"2026-04-23T15:21:46.695671+08:00"},{"id":"1965adf7cfc65447e3c1ae21fbf6d1c5","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"39-59","gmt_create":"2026-04-23T15:21:46.696432+08:00","gmt_modified":"2026-04-23T15:21:46.696432+08:00"},{"id":"c730faefb34bb87c40c5f636b4ff7f41","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"80-94","gmt_create":"2026-04-23T15:21:46.697413+08:00","gmt_modified":"2026-04-23T15:21:46.697413+08:00"},{"id":"b9978c3eccea3ef566b003216e5047af","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"61-78","gmt_create":"2026-04-23T15:21:46.698274+08:00","gmt_modified":"2026-04-23T15:21:46.698274+08:00"},{"id":"eb6ff4361d7413b57f1f70b1ec2f0c94","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"96-111","gmt_create":"2026-04-23T15:21:46.699021+08:00","gmt_modified":"2026-04-23T15:21:46.699021+08:00"},{"id":"f6c9f1b4e8646c366a31426a4537675d","path":"backend/app/models/query_task.py","line_range":"36-38","gmt_create":"2026-04-23T15:21:46.700462+08:00","gmt_modified":"2026-04-23T15:21:46.700462+08:00"},{"id":"a2adbf02c71e4eb2cf1f120e1a2ff517","path":"backend/app/models/citation_record.py","line_range":"37-41","gmt_create":"2026-04-23T15:21:46.70082+08:00","gmt_modified":"2026-04-23T15:21:46.700821+08:00"},{"id":"0907fc2974ec31c23aaaef02076700a1","path":"backend/app/models/user.py","line_range":"25-33","gmt_create":"2026-04-23T15:21:46.702342+08:00","gmt_modified":"2026-04-23T15:21:46.702342+08:00"},{"id":"842f74e2cc054608242e93fbefd96b45","path":"backend/app/models/query.py","line_range":"32-40","gmt_create":"2026-04-23T15:21:46.702652+08:00","gmt_modified":"2026-04-23T15:21:46.702652+08:00"},{"id":"aed9e839038c45e6ce2023c4e05adb76","path":"backend/app/models/query_task.py","line_range":"27-32","gmt_create":"2026-04-23T15:21:46.702999+08:00","gmt_modified":"2026-04-23T15:21:46.703+08:00"},{"id":"2181318c993526c86458f5eef134aed6","path":"backend/app/services/query.py","line_range":"62-77","gmt_create":"2026-04-23T15:21:46.703419+08:00","gmt_modified":"2026-04-23T15:21:46.703419+08:00"},{"id":"a817488dc968d761a8977fb5bb8d01a2","path":"backend/app/services/query.py","line_range":"45-129","gmt_create":"2026-04-23T15:21:46.703795+08:00","gmt_modified":"2026-04-23T15:21:46.703795+08:00"},{"id":"d20fc729a5d3986b1c077f9e07ece9c4","path":"backend/app/config.py","line_range":"7","gmt_create":"2026-04-23T15:21:46.704958+08:00","gmt_modified":"2026-04-23T15:21:46.704958+08:00"},{"id":"ea655c6d147bc98beb42955d437260cc","path":"backend/app/config.py","line_range":"1-23","gmt_create":"2026-04-23T15:21:46.705746+08:00","gmt_modified":"2026-04-23T15:21:46.705746+08:00"},{"id":"37868a5af96edcdad149caf9a184435a","path":"backend/app/api/queries.py","line_range":"42-85","gmt_create":"2026-04-23T15:21:46.706426+08:00","gmt_modified":"2026-04-23T15:21:46.706426+08:00"},{"id":"601b981b00d93b941843f046a163d5a3","path":"backend/app/schemas/query.py","line_range":"18-33","gmt_create":"2026-04-23T15:21:46.706755+08:00","gmt_modified":"2026-04-23T15:21:46.706755+08:00"},{"id":"290df8332b3d104e5ea8d71dc39315b5","path":"tests/conftest.py","line_range":"1-123","gmt_create":"2026-04-23T15:22:15.985975+08:00","gmt_modified":"2026-04-23T15:22:15.985975+08:00"},{"id":"c2747ca16b879bca0f68955534c3c4fc","path":"backend/app/main.py","line_range":"1-48","gmt_create":"2026-04-23T15:22:15.986592+08:00","gmt_modified":"2026-04-23T15:22:15.986592+08:00"},{"id":"76e6c0abb49fec57cac4892837a143c9","path":"backend/app/api/deps.py","line_range":"1-43","gmt_create":"2026-04-23T15:22:15.987077+08:00","gmt_modified":"2026-04-23T15:22:15.987077+08:00"},{"id":"f66d9907b467b110c638bd527efd95c5","path":"backend/app/api/auth.py","line_range":"1-43","gmt_create":"2026-04-23T15:22:15.987417+08:00","gmt_modified":"2026-04-23T15:22:15.987417+08:00"},{"id":"116584ea9162c1bc05911f39f9ef82b6","path":"backend/app/workers/citation_engine.py","line_range":"1-309","gmt_create":"2026-04-23T15:22:15.988451+08:00","gmt_modified":"2026-04-23T15:22:15.988451+08:00"},{"id":"9630036e63fc15cb81b202cf79671aab","path":"backend/app/workers/scheduler.py","line_range":"1-182","gmt_create":"2026-04-23T15:22:15.988885+08:00","gmt_modified":"2026-04-23T15:22:15.988885+08:00"},{"id":"84fbed7d35f7752e2117a74fcaf5f0e9","path":"backend/app/config.py","line_range":"1-17","gmt_create":"2026-04-23T15:22:15.989594+08:00","gmt_modified":"2026-04-23T15:22:15.989594+08:00"},{"id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","path":"tests/conftest.py","line_range":"19-123","gmt_create":"2026-04-23T15:22:15.990689+08:00","gmt_modified":"2026-04-23T15:22:15.990689+08:00"},{"id":"9df233ef1be4b95068ed91bf01083ae7","path":"tests/conftest.py","line_range":"117-123","gmt_create":"2026-04-23T15:22:15.99106+08:00","gmt_modified":"2026-04-23T15:22:15.99106+08:00"},{"id":"6286d4be455dc058c8be2ee4e0d1175a","path":"backend/app/main.py","line_range":"38-42","gmt_create":"2026-04-23T15:22:15.991399+08:00","gmt_modified":"2026-04-23T15:22:15.991399+08:00"},{"id":"069243fafe60a85cf16a0ca40fa07180","path":"backend/app/api/deps.py","line_range":"16-43","gmt_create":"2026-04-23T15:22:15.991722+08:00","gmt_modified":"2026-04-23T15:22:15.991722+08:00"},{"id":"d5a1fb0bd23ce9240fbf79529ef94a45","path":"backend/app/api/auth.py","line_range":"13-43","gmt_create":"2026-04-23T15:22:15.992045+08:00","gmt_modified":"2026-04-23T15:22:15.992045+08:00"},{"id":"735aef72b4fe6ca4f407e69b7dda8b43","path":"backend/app/api/citations.py","line_range":"25-78","gmt_create":"2026-04-23T15:22:15.992721+08:00","gmt_modified":"2026-04-23T15:22:15.992721+08:00"},{"id":"8128dd67cf376d2cadf7c2d3831c380a","path":"backend/app/database.py","line_range":"23-29","gmt_create":"2026-04-23T15:22:15.993159+08:00","gmt_modified":"2026-04-23T15:22:15.993159+08:00"},{"id":"1721defc3d6206478d3c0692cc821761","path":"tests/test_auth.py","line_range":"25-104","gmt_create":"2026-04-23T15:22:15.9936+08:00","gmt_modified":"2026-04-23T15:22:15.9936+08:00"},{"id":"753a437d837246ead62b0e16c6331284","path":"backend/app/services/auth.py","line_range":"37-69","gmt_create":"2026-04-23T15:22:15.994329+08:00","gmt_modified":"2026-04-23T15:22:15.994329+08:00"},{"id":"d820e2daf2ea133a7aa17cdc475e44a4","path":"tests/test_auth.py","line_range":"1-104","gmt_create":"2026-04-23T15:22:15.99504+08:00","gmt_modified":"2026-04-23T15:22:15.99504+08:00"},{"id":"1a439c5fed6cfd188c646e1614d56371","path":"backend/app/services/auth.py","line_range":"1-69","gmt_create":"2026-04-23T15:22:15.995715+08:00","gmt_modified":"2026-04-23T15:22:15.995715+08:00"},{"id":"5c67e2f70283956b2d29a3c1443eb514","path":"backend/app/workers/citation_engine.py","line_range":"122-146","gmt_create":"2026-04-23T15:22:15.996787+08:00","gmt_modified":"2026-04-23T15:22:15.996787+08:00"},{"id":"a57acd9da5287c915ac823784a409292","path":"tests/test_citation_engine.py","line_range":"1-127","gmt_create":"2026-04-23T15:22:15.99744+08:00","gmt_modified":"2026-04-23T15:22:15.99744+08:00"},{"id":"2a4f741f31f62dce8ad63be2e831f520","path":"tests/test_citations.py","line_range":"23-93","gmt_create":"2026-04-23T15:22:15.998141+08:00","gmt_modified":"2026-04-23T15:22:15.998141+08:00"},{"id":"692ac240965eff7e66945aa3c4c270f7","path":"tests/test_citations.py","line_range":"1-93","gmt_create":"2026-04-23T15:22:15.998797+08:00","gmt_modified":"2026-04-23T15:22:15.998797+08:00"},{"id":"32a0a52faca2d8d488e49c63c86075b1","path":"tests/test_queries.py","line_range":"29-154","gmt_create":"2026-04-23T15:22:15.999443+08:00","gmt_modified":"2026-04-23T15:22:15.999444+08:00"},{"id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","path":"tests/test_queries.py","line_range":"1-154","gmt_create":"2026-04-23T15:22:16.000539+08:00","gmt_modified":"2026-04-23T15:22:16.000539+08:00"},{"id":"3a6e1b738967bf8cc651e57f48e2e126","path":"tests/test_business_flow.py","line_range":"83-126","gmt_create":"2026-04-23T15:22:16.00171+08:00","gmt_modified":"2026-04-23T15:22:16.00171+08:00"},{"id":"b1afd377757f1d0e9bdf87edfff3ad88","path":"tests/test_business_flow.py","line_range":"131-186","gmt_create":"2026-04-23T15:22:16.002219+08:00","gmt_modified":"2026-04-23T15:22:16.002219+08:00"},{"id":"de05ec7eed033e432991e5a88e1b5a06","path":"tests/test_business_flow.py","line_range":"192-222","gmt_create":"2026-04-23T15:22:16.002653+08:00","gmt_modified":"2026-04-23T15:22:16.002653+08:00"},{"id":"7fd61a451248b6b129299d6246f711c7","path":"tests/test_business_flow.py","line_range":"228-296","gmt_create":"2026-04-23T15:22:16.003121+08:00","gmt_modified":"2026-04-23T15:22:16.003121+08:00"},{"id":"53eedffff456a566fa7b0cecc7169f56","path":"tests/test_business_flow.py","line_range":"1-441","gmt_create":"2026-04-23T15:22:16.003614+08:00","gmt_modified":"2026-04-23T15:22:16.003615+08:00"},{"id":"906f7a8288e38d4244211f3f538fe7b6","path":"backend/app/workers/scheduler.py","line_range":"27-182","gmt_create":"2026-04-23T15:22:16.004044+08:00","gmt_modified":"2026-04-23T15:22:16.004044+08:00"},{"id":"1647ee2066de2ae59ba8cf88e33c5e02","path":"tests/test_scheduler.py","line_range":"1-123","gmt_create":"2026-04-23T15:22:16.004461+08:00","gmt_modified":"2026-04-23T15:22:16.004461+08:00"},{"id":"fd18328b6582e68c30b130b912891992","path":"frontend/components/providers.tsx","line_range":"1-9","gmt_create":"2026-04-23T15:22:23.501815+08:00","gmt_modified":"2026-04-23T15:22:23.501815+08:00"},{"id":"71a37a516437e94fd82a87efc70a3f16","path":"frontend/package.json","line_range":"1-40","gmt_create":"2026-04-23T15:22:23.503888+08:00","gmt_modified":"2026-04-23T15:22:23.503888+08:00"},{"id":"89d70e5f89be23a229e3ee59982b8e6e","path":"frontend/tailwind.config.ts","line_range":"1-57","gmt_create":"2026-04-23T15:22:23.504853+08:00","gmt_modified":"2026-04-23T15:22:23.504853+08:00"},{"id":"95be577a89fbeb02578e4c3718c6ec86","path":"frontend/components/ui/button.tsx","line_range":"1-57","gmt_create":"2026-04-23T15:22:23.505579+08:00","gmt_modified":"2026-04-23T15:22:23.505579+08:00"},{"id":"607bb628918a7a5d54cbf74763f94d07","path":"frontend/components/ui/input.tsx","line_range":"1-23","gmt_create":"2026-04-23T15:22:23.506257+08:00","gmt_modified":"2026-04-23T15:22:23.506257+08:00"},{"id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","path":"frontend/components/ui/select.tsx","line_range":"1-161","gmt_create":"2026-04-23T15:22:23.507044+08:00","gmt_modified":"2026-04-23T15:22:23.507044+08:00"},{"id":"ad6ff021b2126ad5c42323305eb6d8b0","path":"frontend/components/ui/dropdown-menu.tsx","line_range":"1-201","gmt_create":"2026-04-23T15:22:23.507926+08:00","gmt_modified":"2026-04-23T15:22:23.507926+08:00"},{"id":"a85f004dca63614b4e734ba63b45ef9e","path":"frontend/components/ui/card.tsx","line_range":"1-80","gmt_create":"2026-04-23T15:22:23.508411+08:00","gmt_modified":"2026-04-23T15:22:23.508411+08:00"},{"id":"bd3042a8d9b602334720b0d7b4e8ab3d","path":"frontend/components/ui/tabs.tsx","line_range":"1-56","gmt_create":"2026-04-23T15:22:23.509355+08:00","gmt_modified":"2026-04-23T15:22:23.509355+08:00"},{"id":"379443f450513b5492e2d9d5fca94a42","path":"frontend/components/ui/label.tsx","line_range":"1-27","gmt_create":"2026-04-23T15:22:23.509832+08:00","gmt_modified":"2026-04-23T15:22:23.509832+08:00"},{"id":"4aa6ad434a73143bb7a2072124f63be0","path":"frontend/components/ui/badge.tsx","line_range":"1-37","gmt_create":"2026-04-23T15:22:23.510286+08:00","gmt_modified":"2026-04-23T15:22:23.510286+08:00"},{"id":"c45dbdda70a8b9f02b52af4991644d0b","path":"frontend/package.json","line_range":"11-27","gmt_create":"2026-04-23T15:22:23.511056+08:00","gmt_modified":"2026-04-23T15:22:23.511056+08:00"},{"id":"6ac6943c93570294e4fb15a862be2616","path":"frontend/components/ui/button.tsx","line_range":"36-54","gmt_create":"2026-04-23T15:22:23.51229+08:00","gmt_modified":"2026-04-23T15:22:23.51229+08:00"},{"id":"4bfb5059c685e9878aed64cb5347ccec","path":"frontend/components/ui/dialog.tsx","line_range":"9-54","gmt_create":"2026-04-23T15:22:23.513266+08:00","gmt_modified":"2026-04-23T15:22:23.513266+08:00"},{"id":"0af48b69fe8fb9e480fa1656f36a4330","path":"frontend/components/ui/dropdown-menu.tsx","line_range":"21-75","gmt_create":"2026-04-23T15:22:23.514127+08:00","gmt_modified":"2026-04-23T15:22:23.514127+08:00"},{"id":"09971e31ab658e119d4c0ad948282107","path":"frontend/components/ui/select.tsx","line_range":"15-100","gmt_create":"2026-04-23T15:22:23.514956+08:00","gmt_modified":"2026-04-23T15:22:23.514956+08:00"},{"id":"31aa8777de6043883950d2668094e388","path":"frontend/components/ui/table.tsx","line_range":"5-106","gmt_create":"2026-04-23T15:22:23.515769+08:00","gmt_modified":"2026-04-23T15:22:23.515769+08:00"},{"id":"28baf3cedb89a21c6d542b7ce2439b24","path":"frontend/components/ui/tabs.tsx","line_range":"8-53","gmt_create":"2026-04-23T15:22:23.516573+08:00","gmt_modified":"2026-04-23T15:22:23.516573+08:00"},{"id":"28b0f4797c6084272244175a24b961cb","path":"frontend/components/ui/card.tsx","line_range":"5-77","gmt_create":"2026-04-23T15:22:23.518527+08:00","gmt_modified":"2026-04-23T15:22:23.518527+08:00"},{"id":"a6e0b3fa65906c3c3cd88707e1d40059","path":"frontend/components/ui/label.tsx","line_range":"9-23","gmt_create":"2026-04-23T15:22:23.520181+08:00","gmt_modified":"2026-04-23T15:22:23.520181+08:00"},{"id":"9a909775022010b4686c2b00cdf1c165","path":"frontend/components/ui/badge.tsx","line_range":"6-34","gmt_create":"2026-04-23T15:22:23.521343+08:00","gmt_modified":"2026-04-23T15:22:23.521343+08:00"},{"id":"ce1cd184945ae56cf63f55168afd8050","path":"frontend/components/ui/dialog.tsx","line_range":"47-50","gmt_create":"2026-04-23T15:22:23.523823+08:00","gmt_modified":"2026-04-23T15:22:23.523823+08:00"},{"id":"4a2a06e1efcbc85deaa013dca155f20c","path":"frontend/tailwind.config.ts","line_range":"10-54","gmt_create":"2026-04-23T15:22:23.524333+08:00","gmt_modified":"2026-04-23T15:22:23.524333+08:00"},{"id":"8b00ea4aba57ea6ed982287fb7840805","path":"frontend/lib/utils.ts","line_range":"4-6","gmt_create":"2026-04-23T15:22:23.524876+08:00","gmt_modified":"2026-04-23T15:22:23.524876+08:00"},{"id":"7c0831c17e8c65eaed9511e17ed2a2ef","path":"backend/app/services/citation.py","line_range":"1-269","gmt_create":"2026-04-23T20:31:36.482111+08:00","gmt_modified":"2026-04-23T20:31:36.482111+08:00"},{"id":"71f98c8993fb42b108e34a554247869b","path":"backend/app/workers/scheduler.py","line_range":"1-95","gmt_create":"2026-04-23T20:31:36.482732+08:00","gmt_modified":"2026-04-23T20:31:36.482732+08:00"},{"id":"8d5aac2ae0671f05d7c0807ba9296cdf","path":"backend/app/workers/citation_engine.py","line_range":"1-330","gmt_create":"2026-04-23T20:31:36.4831+08:00","gmt_modified":"2026-04-23T20:31:36.4831+08:00"},{"id":"debd789847d1eed2d54198772edf68a2","path":"backend/app/workers/platforms/tongyi.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.483423+08:00","gmt_modified":"2026-04-23T20:31:36.483423+08:00"},{"id":"3bde521d18cc7221ae2f14637e163aac","path":"backend/app/workers/platforms/doubao.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.483821+08:00","gmt_modified":"2026-04-23T20:31:36.483821+08:00"},{"id":"c26862d9e0fc878b51a2668cfd2ec827","path":"backend/app/workers/platforms/qingyan.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.484113+08:00","gmt_modified":"2026-04-23T20:31:36.484114+08:00"},{"id":"0fcc9c2e0d33b887c5f18a3807b64a1e","path":"backend/app/workers/platforms/tiangong.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.484512+08:00","gmt_modified":"2026-04-23T20:31:36.484512+08:00"},{"id":"a4baa2444208b3f9a3f42bc492038207","path":"backend/app/workers/platforms/xinghuo.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.485041+08:00","gmt_modified":"2026-04-23T20:31:36.485041+08:00"},{"id":"9f82f6d82bf914a608d6afa3d9854abf","path":"backend/app/workers/platforms/search_engine.py","line_range":"1-174","gmt_create":"2026-04-23T20:31:36.485492+08:00","gmt_modified":"2026-04-23T20:31:36.485492+08:00"},{"id":"6281fff17a86ec1895c64d87c2ae7fb1","path":"backend/app/models/query.py","line_range":"1-55","gmt_create":"2026-04-23T20:31:36.486251+08:00","gmt_modified":"2026-04-23T20:31:36.486251+08:00"},{"id":"943c18db69a04b3137fba4cebcfea87e","path":"backend/app/models/citation_record.py","line_range":"1-42","gmt_create":"2026-04-23T20:31:36.48687+08:00","gmt_modified":"2026-04-23T20:31:36.48687+08:00"},{"id":"6628e006b8e5ca16160743528b6b0506","path":"backend/app/models/query_task.py","line_range":"1-39","gmt_create":"2026-04-23T20:31:36.487305+08:00","gmt_modified":"2026-04-23T20:31:36.487305+08:00"},{"id":"72a110dca58d8152758e2fdab4e94761","path":"backend/app/workers/platforms/base.py","line_range":"1-18","gmt_create":"2026-04-23T20:31:36.490327+08:00","gmt_modified":"2026-04-23T20:31:36.490328+08:00"},{"id":"300e43c7a648440163f81039eaa47b5a","path":"frontend/lib/platforms.ts","line_range":"1-24","gmt_create":"2026-04-23T20:31:36.494718+08:00","gmt_modified":"2026-04-23T20:31:36.494718+08:00"},{"id":"caf1970ded8fc5d3921005e166e2100b","path":"backend/app/api/citations.py","line_range":"59-78","gmt_create":"2026-04-23T20:31:36.499676+08:00","gmt_modified":"2026-04-23T20:31:36.499677+08:00"},{"id":"4ded871d02b8119cdd985de8b220b084","path":"backend/app/services/citation.py","line_range":"204-234","gmt_create":"2026-04-23T20:31:36.500626+08:00","gmt_modified":"2026-04-23T20:31:36.500626+08:00"},{"id":"448970b02d89d5e1576f70bdb0063363","path":"backend/app/workers/scheduler.py","line_range":"51-84","gmt_create":"2026-04-23T20:31:36.501136+08:00","gmt_modified":"2026-04-23T20:31:36.501136+08:00"},{"id":"362d22f423631cda39404660b3317a2f","path":"backend/app/workers/citation_engine.py","line_range":"177-254","gmt_create":"2026-04-23T20:31:36.501596+08:00","gmt_modified":"2026-04-23T20:31:36.501596+08:00"},{"id":"b475ff5225ac403c7fcf3dd7e14cbac6","path":"backend/app/workers/platforms/tongyi.py","line_range":"16-33","gmt_create":"2026-04-23T20:31:36.502032+08:00","gmt_modified":"2026-04-23T20:31:36.502032+08:00"},{"id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","path":"backend/app/workers/platforms/search_engine.py","line_range":"163-174","gmt_create":"2026-04-23T20:31:36.502504+08:00","gmt_modified":"2026-04-23T20:31:36.502504+08:00"},{"id":"75c6ab0599d304bf36d290d4143d3d2f","path":"backend/app/models/query.py","line_range":"29-31","gmt_create":"2026-04-23T20:31:36.502934+08:00","gmt_modified":"2026-04-23T20:31:36.502934+08:00"},{"id":"2a6780838f1415dcb7d0fa611f64cee7","path":"backend/app/workers/platforms/base.py","line_range":"4-17","gmt_create":"2026-04-23T20:31:36.504228+08:00","gmt_modified":"2026-04-23T20:31:36.504228+08:00"},{"id":"c5ae7697193b2b93425ff25d2d7d54a9","path":"backend/app/workers/platforms/tongyi.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505069+08:00","gmt_modified":"2026-04-23T20:31:36.505069+08:00"},{"id":"aa8c3fa3bc509dafe64d113bdd09eafa","path":"backend/app/workers/platforms/doubao.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505502+08:00","gmt_modified":"2026-04-23T20:31:36.505503+08:00"},{"id":"eabb031e538ea62cab69b01368740d20","path":"backend/app/workers/platforms/qingyan.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505932+08:00","gmt_modified":"2026-04-23T20:31:36.505932+08:00"},{"id":"b1c09e372a63e9854886adaea1663bea","path":"backend/app/workers/platforms/tiangong.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.50633+08:00","gmt_modified":"2026-04-23T20:31:36.50633+08:00"},{"id":"79793bcd507f9d287d19014b60d963d3","path":"backend/app/workers/platforms/xinghuo.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.506717+08:00","gmt_modified":"2026-04-23T20:31:36.506717+08:00"},{"id":"102223dd13475177a1ade8b9be14fbd1","path":"backend/app/workers/platforms/search_engine.py","line_range":"79-144","gmt_create":"2026-04-23T20:31:36.509667+08:00","gmt_modified":"2026-04-23T20:31:36.509667+08:00"},{"id":"8565f299083b4dcba5a328c947f06fee","path":"backend/app/workers/citation_engine.py","line_range":"256-287","gmt_create":"2026-04-23T20:31:36.512515+08:00","gmt_modified":"2026-04-23T20:31:36.512515+08:00"},{"id":"8af91caf063c12c8236f9675769ce4a1","path":"tests/test_citation_engine.py","line_range":"1-54","gmt_create":"2026-04-23T20:31:36.51401+08:00","gmt_modified":"2026-04-23T20:31:36.51401+08:00"},{"id":"005172b71dc742cf6803c5eb0185091e","path":"backend/requirements.txt","line_range":"1-36","gmt_create":"2026-04-23T20:31:36.516249+08:00","gmt_modified":"2026-04-23T20:31:36.516249+08:00"},{"id":"b55cc5936c299f819b57b899858438e6","path":"backend/app/workers/platforms/search_engine.py","line_range":"139-144","gmt_create":"2026-04-23T20:31:36.518228+08:00","gmt_modified":"2026-04-23T20:31:36.518228+08:00"},{"id":"384b1939e53970ce7ae75d241a49da5f","path":"backend/app/workers/platforms/tongyi.py","line_range":"22-29","gmt_create":"2026-04-23T20:31:36.518493+08:00","gmt_modified":"2026-04-23T20:31:36.518493+08:00"},{"id":"f096aa3ea82e9fa625a9acb1309b4c50","path":"backend/app/workers/citation_engine.py","line_range":"231-247","gmt_create":"2026-04-23T20:31:36.518795+08:00","gmt_modified":"2026-04-23T20:31:36.518795+08:00"},{"id":"15b8ebf74b0a5dfac58024d323ca8d0a","path":"backend/app/workers/citation_engine.py","line_range":"164-175","gmt_create":"2026-04-23T20:31:36.519395+08:00","gmt_modified":"2026-04-23T20:31:36.519395+08:00"},{"id":"bcfade20d923c8efa713808ca9af94ca","path":"backend/app/workers/platforms/wenxin.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:50.45294+08:00","gmt_modified":"2026-04-23T20:31:50.45294+08:00"},{"id":"ca7e1232fbba5fb75e04ab8e491bfbd1","path":"backend/app/workers/platforms/kimi.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:50.453339+08:00","gmt_modified":"2026-04-23T20:31:50.453339+08:00"},{"id":"9720b93ed7247efb685e2825e5f964bf","path":"backend/app/workers/citation_engine.py","line_range":"161-176","gmt_create":"2026-04-23T20:31:50.454207+08:00","gmt_modified":"2026-04-23T20:31:50.454207+08:00"},{"id":"0d226400124ba891a46f59c36781ccd8","path":"backend/app/config.py","line_range":"9-23","gmt_create":"2026-04-23T20:31:50.454503+08:00","gmt_modified":"2026-04-23T20:31:50.454503+08:00"},{"id":"412695e5de2014514a8f62f98c573656","path":"backend/Dockerfile","line_range":"1-41","gmt_create":"2026-04-23T20:31:50.454798+08:00","gmt_modified":"2026-04-23T20:31:50.454798+08:00"},{"id":"485e15eb30a5b08da38a628c9dd5053e","path":"backend/app/workers/platforms/search_engine.py","line_range":"16-77","gmt_create":"2026-04-23T20:31:50.459138+08:00","gmt_modified":"2026-04-23T20:31:50.459138+08:00"},{"id":"77158a6f887e224a03552893bfec7c92","path":"backend/app/workers/platforms/wenxin.py","line_range":"16-33","gmt_create":"2026-04-23T20:31:50.461662+08:00","gmt_modified":"2026-04-23T20:31:50.461662+08:00"},{"id":"5c3f336b5a7b4af4cc2f2ac183539218","path":"backend/app/workers/platforms/search_engine.py","line_range":"79-145","gmt_create":"2026-04-23T20:31:50.464823+08:00","gmt_modified":"2026-04-23T20:31:50.464823+08:00"},{"id":"3894c1ed9dca2ebf2359f40ebdb1959e","path":"backend/app/workers/platforms/search_engine.py","line_range":"147-174","gmt_create":"2026-04-23T20:31:50.465221+08:00","gmt_modified":"2026-04-23T20:31:50.465221+08:00"},{"id":"e27bcba24aaadeec1922d2b4e5b8386b","path":"backend/app/api/queries.py","line_range":"1-109","gmt_create":"2026-04-23T20:31:50.46721+08:00","gmt_modified":"2026-04-23T20:31:50.46721+08:00"},{"id":"5f893f5078aa8e549284feb057aa45da","path":"backend/app/workers/platforms/wenxin.py","line_range":"16-29","gmt_create":"2026-04-23T20:31:50.469467+08:00","gmt_modified":"2026-04-23T20:31:50.469467+08:00"},{"id":"e0b68d2d24760689a0f4f00dfee5f9f2","path":"backend/app/workers/platforms/search_engine.py","line_range":"28-76","gmt_create":"2026-04-23T20:31:50.470319+08:00","gmt_modified":"2026-04-23T20:31:50.470319+08:00"},{"id":"e9b98ae83632342d8e06cde39e9c9462","path":"backend/app/workers/platforms/search_engine.py","line_range":"105-137","gmt_create":"2026-04-23T20:31:50.470672+08:00","gmt_modified":"2026-04-23T20:31:50.470672+08:00"},{"id":"c86edb7a95fbe4b431ac65a0e2b8636e","path":"backend/app/api/queries.py","line_range":"90-109","gmt_create":"2026-04-23T20:31:50.471824+08:00","gmt_modified":"2026-04-23T20:31:50.471825+08:00"},{"id":"6e054d9a78c0c8c9da8dec4c4bda62ab","path":"backend/app/database.py","line_range":"6-28","gmt_create":"2026-04-23T20:33:29.972803+08:00","gmt_modified":"2026-04-23T20:33:29.972803+08:00"},{"id":"9c16a069e5154660bfdfa48f3518fc6a","path":"backend/app/models/query_task.py","line_range":"11-38","gmt_create":"2026-04-23T20:33:29.980385+08:00","gmt_modified":"2026-04-23T20:33:29.980385+08:00"},{"id":"a4918fcbd21492ad996d7f5496f03a4b","path":"backend/app/workers/platforms/kimi.py","line_range":"33-48","gmt_create":"2026-04-23T20:33:29.982795+08:00","gmt_modified":"2026-04-23T20:33:29.982795+08:00"},{"id":"bc38d046b4b1410ae2165cee2272839e","path":"backend/app/workers/platforms/wenxin.py","line_range":"33-48","gmt_create":"2026-04-23T20:33:29.983597+08:00","gmt_modified":"2026-04-23T20:33:29.983597+08:00"},{"id":"72f6d334026866e8a61d2ffb1d83370a","path":"backend/app/workers/citation_engine.py","line_range":"19-100","gmt_create":"2026-04-23T20:33:29.986927+08:00","gmt_modified":"2026-04-23T20:33:29.986928+08:00"},{"id":"1d84b9a7eb013882953a2d1d948299e4","path":"backend/app/workers/platforms/kimi.py","line_range":"126-197","gmt_create":"2026-04-23T20:33:29.990308+08:00","gmt_modified":"2026-04-23T20:33:29.990308+08:00"},{"id":"ba687f2c64aff92b3906658359ed953a","path":"backend/app/workers/platforms/wenxin.py","line_range":"124-195","gmt_create":"2026-04-23T20:33:29.991213+08:00","gmt_modified":"2026-04-23T20:33:29.991213+08:00"},{"id":"52ee729b02c992c689522c7956c14128","path":"backend/app/workers/scheduler.py","line_range":"57-62","gmt_create":"2026-04-23T20:33:29.992799+08:00","gmt_modified":"2026-04-23T20:33:29.992799+08:00"},{"id":"c9e32b7324cce60c8887deb8404ee759","path":"backend/app/workers/scheduler.py","line_range":"107-112","gmt_create":"2026-04-23T20:33:29.99333+08:00","gmt_modified":"2026-04-23T20:33:29.99333+08:00"},{"id":"8355d3821337334caee57a75dc8c8865","path":"backend/app/services/query.py","line_range":"116-130","gmt_create":"2026-04-23T20:33:29.994505+08:00","gmt_modified":"2026-04-23T20:33:29.994505+08:00"},{"id":"4fe27d4d1323b500e72d870aa6212a1a","path":"backend/app/workers/scheduler.py","line_range":"13-20","gmt_create":"2026-04-23T20:33:29.996199+08:00","gmt_modified":"2026-04-23T20:33:29.996199+08:00"},{"id":"3729543092bccad8926c5ea852db1e69","path":"backend/app/workers/citation_engine.py","line_range":"148-157","gmt_create":"2026-04-23T20:33:29.996517+08:00","gmt_modified":"2026-04-23T20:33:29.996517+08:00"},{"id":"1ee5153c867fc6e9d277a3067963a1fc","path":"backend/app/workers/scheduler.py","line_range":"32-38","gmt_create":"2026-04-23T20:33:29.997154+08:00","gmt_modified":"2026-04-23T20:33:29.997154+08:00"},{"id":"ed527c7a549ec333c2b30b59614343df","path":"backend/app/models/query.py","line_range":"50-54","gmt_create":"2026-04-23T20:33:29.997453+08:00","gmt_modified":"2026-04-23T20:33:29.997453+08:00"},{"id":"1a3351698ecc7cd4e508b7a792804fc4","path":"backend/app/workers/citation_engine.py","line_range":"302-309","gmt_create":"2026-04-23T20:33:29.999284+08:00","gmt_modified":"2026-04-23T20:33:29.999284+08:00"},{"id":"e3e9710c7eead933c936519395f792e0","path":"backend/app/workers/scheduler.py","line_range":"44-49","gmt_create":"2026-04-23T20:33:30.00043+08:00","gmt_modified":"2026-04-23T20:33:30.000431+08:00"},{"id":"a4143cc29b14f1f5bc75a5e021690666","path":"backend/app/workers/platforms/kimi.py","line_range":"23-31","gmt_create":"2026-04-23T20:33:30.001466+08:00","gmt_modified":"2026-04-23T20:33:30.001466+08:00"},{"id":"7192cfda5508e7587efd91d26cf1f018","path":"backend/app/workers/platforms/wenxin.py","line_range":"23-31","gmt_create":"2026-04-23T20:33:30.002099+08:00","gmt_modified":"2026-04-23T20:33:30.002099+08:00"},{"id":"38142b7d7016c5590e638fafcdcb1a19","path":"backend/app/workers/citation_engine.py","line_range":"211-227","gmt_create":"2026-04-23T20:33:30.002775+08:00","gmt_modified":"2026-04-23T20:33:30.002775+08:00"},{"id":"fb5276346dcc4e7044d8765a8572e7a8","path":"backend/app/config.py","line_range":"4-16","gmt_create":"2026-04-23T20:33:30.003374+08:00","gmt_modified":"2026-04-23T20:33:30.003377+08:00"},{"id":"482d573f97b482b99bcde1c399eceb73","path":"backend/app/api/queries.py","line_range":"90-108","gmt_create":"2026-04-23T20:33:37.21132+08:00","gmt_modified":"2026-04-23T20:33:37.21132+08:00"},{"id":"56f44cc97867cee3e5663424134d6072","path":"backend/app/workers/platforms/kimi.py","line_range":"1-37","gmt_create":"2026-04-23T20:33:37.212923+08:00","gmt_modified":"2026-04-23T20:33:37.212923+08:00"},{"id":"2e326ef8322619f1e8b3873022cb0437","path":"backend/app/workers/platforms/wenxin.py","line_range":"1-37","gmt_create":"2026-04-23T20:33:37.213348+08:00","gmt_modified":"2026-04-23T20:33:37.213348+08:00"},{"id":"4cac57dbc530f0335c913ec5725dfa4f","path":"backend/app/workers/scheduler.py","line_range":"1-121","gmt_create":"2026-04-23T20:33:37.215373+08:00","gmt_modified":"2026-04-23T20:33:37.215373+08:00"},{"id":"db174cfe219fc84d0dd26529f047b1d0","path":"backend/app/workers/citation_engine.py","line_range":"161-330","gmt_create":"2026-04-23T20:33:37.22028+08:00","gmt_modified":"2026-04-23T20:33:37.22028+08:00"},{"id":"f36452f78aabfb0c46da03bbe25dff06","path":"backend/app/services/citation.py","line_range":"219-295","gmt_create":"2026-04-23T20:33:37.223165+08:00","gmt_modified":"2026-04-23T20:33:37.223165+08:00"},{"id":"52c01d7b9c17aa16944cbfcf8885be61","path":"backend/app/workers/platforms/kimi.py","line_range":"16-33","gmt_create":"2026-04-23T20:33:37.227954+08:00","gmt_modified":"2026-04-23T20:33:37.227954+08:00"},{"id":"9d352899554ab41b65b2e9f32558d811","path":"backend/app/workers/citation_engine.py","line_range":"39-113","gmt_create":"2026-04-23T20:33:37.229053+08:00","gmt_modified":"2026-04-23T20:33:37.229053+08:00"},{"id":"b1ee5a992230844ba898765be63f7b27","path":"backend/app/workers/citation_engine.py","line_range":"32-133","gmt_create":"2026-04-23T20:33:37.229555+08:00","gmt_modified":"2026-04-23T20:33:37.229555+08:00"},{"id":"cb098a3cd32339e99f755dfd0fc35b5c","path":"tests/test_citation_engine.py","line_range":"6-127","gmt_create":"2026-04-23T20:33:37.230048+08:00","gmt_modified":"2026-04-23T20:33:37.230049+08:00"},{"id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","path":"backend/app/workers/citation_engine.py","line_range":"145-158","gmt_create":"2026-04-23T20:33:37.230491+08:00","gmt_modified":"2026-04-23T20:33:37.230491+08:00"},{"id":"4e9b3d0e94282f4bc6fa500f4eed61a1","path":"backend/app/workers/citation_engine.py","line_range":"135-159","gmt_create":"2026-04-23T20:33:37.231003+08:00","gmt_modified":"2026-04-23T20:33:37.231003+08:00"},{"id":"8e3201561a9dd9a06ee3bf68ffdb3f99","path":"tests/test_citation_engine.py","line_range":"39-109","gmt_create":"2026-04-23T20:33:37.231501+08:00","gmt_modified":"2026-04-23T20:33:37.231501+08:00"},{"id":"c3a417be3d61f5bcd3fbf976e0c4f15a","path":"backend/app/workers/scheduler.py","line_range":"33-121","gmt_create":"2026-04-23T20:33:37.238099+08:00","gmt_modified":"2026-04-23T20:33:37.238099+08:00"},{"id":"7ce954ed7d3bc4dcf78630124cc0dd88","path":"backend/app/services/citation.py","line_range":"264-295","gmt_create":"2026-04-23T20:33:37.244499+08:00","gmt_modified":"2026-04-23T20:33:37.244499+08:00"},{"id":"7289a3568c137c8a671fc8c963bb8d28","path":"backend/requirements.txt","line_range":"1-35","gmt_create":"2026-04-23T20:33:37.24795+08:00","gmt_modified":"2026-04-23T20:33:37.24795+08:00"},{"id":"ef82ce4377c549013c200e19701a6805","path":"backend/app/workers/platforms/kimi.py","line_range":"21-32","gmt_create":"2026-04-23T20:33:37.254004+08:00","gmt_modified":"2026-04-23T20:33:37.254004+08:00"},{"id":"c7986eb1be0ffdd9ec4e243be4270119","path":"backend/app/workers/platforms/wenxin.py","line_range":"21-32","gmt_create":"2026-04-23T20:33:37.254558+08:00","gmt_modified":"2026-04-23T20:33:37.254558+08:00"},{"id":"5563b3bd56550648dc70302c1762ce5a","path":"backend/app/workers/platforms/tongyi.py","line_range":"18-29","gmt_create":"2026-04-23T20:33:37.255643+08:00","gmt_modified":"2026-04-23T20:33:37.255643+08:00"},{"id":"91852ef8dcc844a2f85e9fce0227ab74","path":"backend/app/workers/platforms/doubao.py","line_range":"18-29","gmt_create":"2026-04-23T20:33:37.25603+08:00","gmt_modified":"2026-04-23T20:33:37.25603+08:00"},{"id":"1b46fab9e22f53db30ead5677d03e3e2","path":"backend/app/workers/citation_engine.py","line_range":"11-16","gmt_create":"2026-04-23T20:33:37.256413+08:00","gmt_modified":"2026-04-23T20:33:37.256413+08:00"},{"id":"4a2fa09aa3a948dec5ef8ba873b0e716","path":"backend/app/services/citation.py","line_range":"14-42","gmt_create":"2026-04-23T20:33:37.257057+08:00","gmt_modified":"2026-04-23T20:33:37.257057+08:00"},{"id":"e7afbab5932c93c3469f1a225e6c7156","path":"backend/app/api/citations.py","line_range":"1-55","gmt_create":"2026-04-23T20:33:57.479092+08:00","gmt_modified":"2026-04-23T20:33:57.479092+08:00"},{"id":"a0eac56d622a2fff529bc2b796064bcd","path":"backend/app/schemas/query.py","line_range":"1-94","gmt_create":"2026-04-23T20:33:57.479659+08:00","gmt_modified":"2026-04-23T20:33:57.479659+08:00"},{"id":"174be58163b6f72b4cd4a493f3463ce4","path":"backend/app/schemas/citation.py","line_range":"1-52","gmt_create":"2026-04-23T20:33:57.480222+08:00","gmt_modified":"2026-04-23T20:33:57.480222+08:00"},{"id":"136f172c732d0cc130532a4f0df475a4","path":"backend/app/models/user.py","line_range":"1-41","gmt_create":"2026-04-23T20:33:57.481714+08:00","gmt_modified":"2026-04-23T20:33:57.481714+08:00"},{"id":"916551131bd9ac8c9f9c8bb762af1fa4","path":"backend/app/services/query.py","line_range":"1-130","gmt_create":"2026-04-23T20:33:57.482172+08:00","gmt_modified":"2026-04-23T20:33:57.482172+08:00"},{"id":"5d2836286eb7d4eb6039b004a9744d26","path":"backend/app/services/citation.py","line_range":"1-429","gmt_create":"2026-04-23T20:33:57.482643+08:00","gmt_modified":"2026-04-23T20:33:57.482643+08:00"},{"id":"39a3b2d9301fa4eff7bef0fda3352790","path":"backend/app/workers/platforms/kimi.py","line_range":"1-206","gmt_create":"2026-04-23T20:33:57.484464+08:00","gmt_modified":"2026-04-23T20:33:57.484464+08:00"},{"id":"fbcfae3b1238b3da5329ebafe4294861","path":"backend/app/workers/platforms/wenxin.py","line_range":"1-205","gmt_create":"2026-04-23T20:33:57.484977+08:00","gmt_modified":"2026-04-23T20:33:57.484977+08:00"},{"id":"c4273407c88f470df7daf6a8ad5ce969","path":"backend/app/api/queries.py","line_range":"15-109","gmt_create":"2026-04-23T20:33:57.485748+08:00","gmt_modified":"2026-04-23T20:33:57.485748+08:00"},{"id":"35774e0a09ac5459c868914d7182ca95","path":"backend/app/api/citations.py","line_range":"19-55","gmt_create":"2026-04-23T20:33:57.486195+08:00","gmt_modified":"2026-04-23T20:33:57.486195+08:00"},{"id":"f639b566c26dfd18b24e3dfd2e9853ac","path":"backend/app/schemas/citation.py","line_range":"7-52","gmt_create":"2026-04-23T20:33:57.486916+08:00","gmt_modified":"2026-04-23T20:33:57.486916+08:00"},{"id":"b46654006178160f12897e2c5baac8fa","path":"backend/app/services/citation.py","line_range":"219-429","gmt_create":"2026-04-23T20:33:57.488934+08:00","gmt_modified":"2026-04-23T20:33:57.488934+08:00"},{"id":"82265d393c20d0af96beec6b9c657c27","path":"backend/app/api/queries.py","line_range":"28-41","gmt_create":"2026-04-23T20:33:57.49175+08:00","gmt_modified":"2026-04-23T20:33:57.49175+08:00"},{"id":"93e5c95b1691bb81a36bf9a0ac889030","path":"backend/app/services/citation.py","line_range":"219-261","gmt_create":"2026-04-23T20:33:57.493276+08:00","gmt_modified":"2026-04-23T20:33:57.493276+08:00"},{"id":"374200f0bf946f0399351756977d0495","path":"backend/app/workers/citation_engine.py","line_range":"176-234","gmt_create":"2026-04-23T20:33:57.498134+08:00","gmt_modified":"2026-04-23T20:33:57.498134+08:00"},{"id":"9a8d9100a6bc34ebae9ee065def7e88a","path":"backend/app/schemas/query.py","line_range":"44-72","gmt_create":"2026-04-23T20:33:57.500036+08:00","gmt_modified":"2026-04-23T20:33:57.500036+08:00"},{"id":"93c23bcc3456826af17e26a6d4c32116","path":"backend/app/schemas/query.py","line_range":"6-9","gmt_create":"2026-04-23T20:33:57.500633+08:00","gmt_modified":"2026-04-23T20:33:57.500633+08:00"},{"id":"c17eeb8726297096cd5542283f11494f","path":"backend/app/api/queries.py","line_range":"17-109","gmt_create":"2026-04-23T20:33:57.5019+08:00","gmt_modified":"2026-04-23T20:33:57.5019+08:00"},{"id":"08fec4718be6991260c00ca532f9173a","path":"backend/app/api/citations.py","line_range":"22-55","gmt_create":"2026-04-23T20:33:57.502347+08:00","gmt_modified":"2026-04-23T20:33:57.502347+08:00"},{"id":"08007199eea846dd14f15f7dc70419e2","path":"backend/app/schemas/citation.py","line_range":"48-52","gmt_create":"2026-04-23T20:33:57.50265+08:00","gmt_modified":"2026-04-23T20:33:57.50265+08:00"},{"id":"4caff756fd4da029bd64cd16e7ef5960","path":"backend/app/api/queries.py","line_range":"32-39","gmt_create":"2026-04-23T20:33:57.50293+08:00","gmt_modified":"2026-04-23T20:33:57.50293+08:00"},{"id":"b0220895f66f1273966ad5b2c3266952","path":"backend/app/api/queries.py","line_range":"49-53","gmt_create":"2026-04-23T20:33:57.503622+08:00","gmt_modified":"2026-04-23T20:33:57.503622+08:00"},{"id":"44f88f9664fdf6e84ffb7e0675a86a28","path":"backend/app/api/queries.py","line_range":"64-69","gmt_create":"2026-04-23T20:33:57.504188+08:00","gmt_modified":"2026-04-23T20:33:57.504188+08:00"},{"id":"91f280f51389bd1cf711dcf33a4da681","path":"backend/app/api/queries.py","line_range":"79-84","gmt_create":"2026-04-23T20:33:57.504712+08:00","gmt_modified":"2026-04-23T20:33:57.504712+08:00"},{"id":"ab50466a57c77659d7b469d3a8a04ddb","path":"backend/app/api/queries.py","line_range":"96-103","gmt_create":"2026-04-23T20:33:57.505025+08:00","gmt_modified":"2026-04-23T20:33:57.505025+08:00"},{"id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","path":"backend/app/api/citations.py","line_range":"65-71","gmt_create":"2026-04-23T20:33:57.505311+08:00","gmt_modified":"2026-04-23T20:33:57.505311+08:00"},{"id":"82386bc7ca57d9ccc94b656e52bc89f6","path":"backend/app/api/queries.py","line_range":"1-14","gmt_create":"2026-04-23T20:33:57.506573+08:00","gmt_modified":"2026-04-23T20:33:57.506573+08:00"},{"id":"7ab79ab21d7d6e4dbcb224572516f6f6","path":"backend/app/api/citations.py","line_range":"1-19","gmt_create":"2026-04-23T20:33:57.507421+08:00","gmt_modified":"2026-04-23T20:33:57.507422+08:00"},{"id":"8433204d7a82a1f480e57df9ceee5581","path":"backend/app/services/query.py","line_range":"1-10","gmt_create":"2026-04-23T20:33:57.507906+08:00","gmt_modified":"2026-04-23T20:33:57.507906+08:00"},{"id":"3957ee6f15a01b7b541490438ef18684","path":"backend/app/services/citation.py","line_range":"1-17","gmt_create":"2026-04-23T20:33:57.508376+08:00","gmt_modified":"2026-04-23T20:33:57.508376+08:00"},{"id":"fcae8d1d281ad7186999cc4ca8e43db7","path":"backend/app/workers/scheduler.py","line_range":"25-39","gmt_create":"2026-04-23T20:33:57.509666+08:00","gmt_modified":"2026-04-23T20:33:57.509666+08:00"},{"id":"ee12a84ac6334b13e20132181454488b","path":"backend/app/workers/scheduler.py","line_range":"13-19","gmt_create":"2026-04-23T20:33:57.510112+08:00","gmt_modified":"2026-04-23T20:33:57.510112+08:00"},{"id":"897e047b94772e5a0ff57cf773a7f965","path":"backend/app/workers/platforms/kimi.py","line_range":"17-32","gmt_create":"2026-04-23T20:33:57.510534+08:00","gmt_modified":"2026-04-23T20:33:57.510534+08:00"},{"id":"53e8ec81b4d2dbb13c831048e5897036","path":"backend/app/workers/platforms/wenxin.py","line_range":"17-32","gmt_create":"2026-04-23T20:33:57.510845+08:00","gmt_modified":"2026-04-23T20:33:57.510845+08:00"},{"id":"fd3145047b9c813cc8e64b9322e531f9","path":"backend/app/services/citation.py","line_range":"219-327","gmt_create":"2026-04-23T20:33:57.516693+08:00","gmt_modified":"2026-04-23T20:33:57.516693+08:00"},{"id":"b09a0f415030d91b25e6cabd8a0a93fc","path":"backend/app/models/query_task.py","line_range":"176-289","gmt_create":"2026-04-23T20:33:57.51758+08:00","gmt_modified":"2026-04-23T20:33:57.51758+08:00"},{"id":"e2168959b26c386940370b5f1bf48d7d","path":"backend/app/models/citation_record.py","line_range":"194-204","gmt_create":"2026-04-23T20:33:57.517939+08:00","gmt_modified":"2026-04-23T20:33:57.517939+08:00"},{"id":"129573d2bbcde48697ed0e75dea12396","path":"backend/app/workers/scheduler.py","line_range":"25-40","gmt_create":"2026-04-23T20:35:18.586153+08:00","gmt_modified":"2026-04-23T20:35:18.586153+08:00"},{"id":"cf18c97a9be6c78aa43cc229ed3dad20","path":"backend/app/workers/citation_engine.py","line_range":"164-173","gmt_create":"2026-04-23T20:35:18.586656+08:00","gmt_modified":"2026-04-23T20:35:18.586656+08:00"},{"id":"3c7ca5d582dca31c2530b1ce9c058e95","path":"backend/app/workers/platforms/kimi.py","line_range":"10-37","gmt_create":"2026-04-23T20:35:18.587239+08:00","gmt_modified":"2026-04-23T20:35:18.587239+08:00"},{"id":"27047f868643e5457d4f242b4298a9f6","path":"frontend/lib/platforms.ts","line_range":"1-23","gmt_create":"2026-04-23T20:35:18.590782+08:00","gmt_modified":"2026-04-23T20:35:18.590782+08:00"},{"id":"1526e4e02133a48eac04befb74ec5bd1","path":"backend/app/workers/citation_engine.py","line_range":"161-173","gmt_create":"2026-04-23T20:35:18.592183+08:00","gmt_modified":"2026-04-23T20:35:18.592183+08:00"},{"id":"98c02d9bb7aa6e2b6be5f7381e64fd99","path":"backend/app/api/queries.py","line_range":"26-39","gmt_create":"2026-04-23T20:35:18.594026+08:00","gmt_modified":"2026-04-23T20:35:18.594026+08:00"},{"id":"2a971cb83924013902324eceeab22559","path":"backend/app/workers/platforms/kimi.py","line_range":"16-29","gmt_create":"2026-04-23T20:35:18.596805+08:00","gmt_modified":"2026-04-23T20:35:18.596805+08:00"},{"id":"99326fedad9275392719105b5b6782d6","path":"backend/app/workers/platforms/kimi.py","line_range":"31-33","gmt_create":"2026-04-23T20:35:18.597389+08:00","gmt_modified":"2026-04-23T20:35:18.597389+08:00"},{"id":"5e5dacc623918c0f1eba234154c99291","path":"backend/app/workers/platforms/search_engine.py","line_range":"16-76","gmt_create":"2026-04-23T20:35:18.598978+08:00","gmt_modified":"2026-04-23T20:35:18.598978+08:00"},{"id":"5be7e6cf82d6359efddaf131aaf92615","path":"backend/app/workers/citation_engine.py","line_range":"323-330","gmt_create":"2026-04-23T20:35:18.604342+08:00","gmt_modified":"2026-04-23T20:35:18.604342+08:00"},{"id":"129b746e71a9013ceb1b0fcc59942b39","path":"backend/app/workers/scheduler.py","line_range":"86-90","gmt_create":"2026-04-23T20:35:18.611167+08:00","gmt_modified":"2026-04-23T20:35:18.611167+08:00"},{"id":"d780e807ee751f39f331a658b47c4ed3","path":"backend/app/services/citation.py","line_range":"24-269","gmt_create":"2026-04-23T20:35:18.619146+08:00","gmt_modified":"2026-04-23T20:35:18.619146+08:00"},{"id":"8eea43550951387ac740b5e3e64c7691","path":"backend/app/workers/platforms/search_engine.py","line_range":"94-96","gmt_create":"2026-04-23T20:35:18.629044+08:00","gmt_modified":"2026-04-23T20:35:18.629044+08:00"},{"id":"37769b7e6b5588be0065681dedf514ed","path":"backend/app/workers/platforms/search_engine.py","line_range":"140-144","gmt_create":"2026-04-23T20:35:18.631486+08:00","gmt_modified":"2026-04-23T20:35:18.631486+08:00"},{"id":"518d184988b97ebc7ef0c0bf5c10f42c","path":"backend/app/workers/platforms/kimi.py","line_range":"24-29","gmt_create":"2026-04-23T20:35:18.631835+08:00","gmt_modified":"2026-04-23T20:35:18.631835+08:00"},{"id":"818504ee2e17d2f9cc8fe115ca321138","path":"backend/app/api/queries.py","line_range":"34-38","gmt_create":"2026-04-23T20:35:18.632132+08:00","gmt_modified":"2026-04-23T20:35:18.632132+08:00"},{"id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","path":"backend/app/api/citations.py","line_range":"25-56","gmt_create":"2026-04-23T20:35:18.633686+08:00","gmt_modified":"2026-04-23T20:35:18.633686+08:00"},{"id":"d4f99d3dd9fe489c354edf5fe2f8803d","path":"backend/app/models/citation_record.py","line_range":"1-44","gmt_create":"2026-04-23T20:35:45.581649+08:00","gmt_modified":"2026-04-23T20:35:45.58165+08:00"},{"id":"86e37040be1aeb400fab9b529f5404c8","path":"backend/app/models/subscription.py","line_range":"1-37","gmt_create":"2026-04-23T20:35:45.583254+08:00","gmt_modified":"2026-04-23T20:35:45.583254+08:00"},{"id":"211463f5b49610f09594c40c0a235943","path":"backend/alembic/env.py","line_range":"1-89","gmt_create":"2026-04-23T20:35:45.584058+08:00","gmt_modified":"2026-04-23T20:35:45.584058+08:00"},{"id":"48d22eaee09e364a293ad6c4750f5c5a","path":"docker-compose.yml","line_range":"1-71","gmt_create":"2026-04-23T20:35:45.587653+08:00","gmt_modified":"2026-04-23T20:35:45.587653+08:00"},{"id":"98cc82f62b83678f06a33cf9231ecdf8","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"1-128","gmt_create":"2026-04-23T20:35:45.597037+08:00","gmt_modified":"2026-04-23T20:35:45.597037+08:00"},{"id":"e1aabd52989e47806fb997157381e1cf","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","line_range":"1-37","gmt_create":"2026-04-23T20:35:45.597747+08:00","gmt_modified":"2026-04-23T20:35:45.597747+08:00"},{"id":"ac77e4875817616194b7b5997d4fb1ae","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"57-94","gmt_create":"2026-04-23T20:35:45.611901+08:00","gmt_modified":"2026-04-23T20:35:45.611901+08:00"},{"id":"0e57efd98dacc85da21f995980371ee4","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","line_range":"21-37","gmt_create":"2026-04-23T20:35:45.61338+08:00","gmt_modified":"2026-04-23T20:35:45.61338+08:00"},{"id":"717eb27184726e4f78d694984d29420c","path":"backend/app/models/citation_record.py","line_range":"37-44","gmt_create":"2026-04-23T20:35:45.615494+08:00","gmt_modified":"2026-04-23T20:35:45.615495+08:00"},{"id":"bfdf3479f244dc6794628d9df10ab6d0","path":"backend/app/models/query.py","line_range":"11-48","gmt_create":"2026-04-23T20:35:45.618458+08:00","gmt_modified":"2026-04-23T20:35:45.618458+08:00"},{"id":"f5f9f0d96263ae84631c7a8d7e9b3648","path":"backend/app/models/citation_record.py","line_range":"11-44","gmt_create":"2026-04-23T20:35:45.61929+08:00","gmt_modified":"2026-04-23T20:35:45.619291+08:00"},{"id":"818d1354dc0665798f3d91a2ca5153d6","path":"backend/app/models/query_task.py","line_range":"11-34","gmt_create":"2026-04-23T20:35:45.620036+08:00","gmt_modified":"2026-04-23T20:35:45.620036+08:00"},{"id":"24aade4c34609a8ab28e4643a3692201","path":"backend/app/models/subscription.py","line_range":"11-36","gmt_create":"2026-04-23T20:35:45.62075+08:00","gmt_modified":"2026-04-23T20:35:45.62075+08:00"},{"id":"d34337b9ff77246979252d2fd8fb8018","path":"backend/alembic/env.py","line_range":"33-88","gmt_create":"2026-04-23T20:35:45.628352+08:00","gmt_modified":"2026-04-23T20:35:45.628353+08:00"},{"id":"eb63042f04a22f9a67bd498df1684d20","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"36-111","gmt_create":"2026-04-23T20:35:45.634829+08:00","gmt_modified":"2026-04-23T20:35:45.634829+08:00"},{"id":"c651c7ad6747a92ee96eabb2eb82afdd","path":"backend/app/database.py","line_range":"12-18","gmt_create":"2026-04-23T20:35:45.637195+08:00","gmt_modified":"2026-04-23T20:35:45.637195+08:00"},{"id":"dd01eee487298a28e950f6345196f1d4","path":"backend/app/services/citation.py","line_range":"30-79","gmt_create":"2026-04-23T20:35:45.637815+08:00","gmt_modified":"2026-04-23T20:35:45.637815+08:00"},{"id":"7dae7237f11c5100bf7889c105193cf6","path":"backend/app/services/query.py","line_range":"12-32","gmt_create":"2026-04-23T20:35:45.638422+08:00","gmt_modified":"2026-04-23T20:35:45.638422+08:00"},{"id":"cc64cf609f5ff218f618e0664ffa7cc7","path":"backend/app/services/citation.py","line_range":"298-308","gmt_create":"2026-04-23T20:35:45.641905+08:00","gmt_modified":"2026-04-23T20:35:45.641905+08:00"},{"id":"ce7e334595a4ce912e0d116314db9a35","path":"backend/app/services/citation.py","line_range":"342-429","gmt_create":"2026-04-23T20:35:45.6442+08:00","gmt_modified":"2026-04-23T20:35:45.6442+08:00"},{"id":"2f46f212597e3c245b9e5dcc5dbc863d","path":"backend/app/schemas/citation.py","line_range":"7-18","gmt_create":"2026-04-23T20:35:45.64501+08:00","gmt_modified":"2026-04-23T20:35:45.64501+08:00"},{"id":"dc40f1dd3e59ee7f046019201068bea1","path":"backend/app/services/citation.py","line_range":"14-22","gmt_create":"2026-04-23T20:35:45.659571+08:00","gmt_modified":"2026-04-23T20:35:45.659571+08:00"},{"id":"01a0c4b40819965823b56e9da858c024","path":"frontend/Dockerfile","line_range":"1-15","gmt_create":"2026-04-23T21:00:59.634151+08:00","gmt_modified":"2026-04-23T21:00:59.634151+08:00"},{"id":"13f6ca76349ef86ae756bb519f122bc5","path":"backend/alembic.ini","line_range":"1-150","gmt_create":"2026-04-23T21:00:59.636129+08:00","gmt_modified":"2026-04-23T21:00:59.636129+08:00"},{"id":"74abd6612105c29b67178fa9dbd04b61","path":"frontend/tsconfig.json","line_range":"1-27","gmt_create":"2026-04-23T21:00:59.639808+08:00","gmt_modified":"2026-04-23T21:00:59.639808+08:00"},{"id":"5bdaabf085a7c3eb6e87c5ad7479e25d","path":"frontend/.eslintrc.json","line_range":"1-4","gmt_create":"2026-04-23T21:00:59.640082+08:00","gmt_modified":"2026-04-23T21:00:59.640082+08:00"},{"id":"9482f4f6279a4f636b77e69b8273b996","path":"backend/alembic.ini","line_range":"86-114","gmt_create":"2026-04-23T21:00:59.64068+08:00","gmt_modified":"2026-04-23T21:00:59.64068+08:00"},{"id":"397b266f19a1addebdf6c32db71ae77f","path":"tests/conftest.py","line_range":"1-71","gmt_create":"2026-04-23T21:00:59.640958+08:00","gmt_modified":"2026-04-23T21:00:59.640958+08:00"},{"id":"eb603ec2611957de67af00756f4b1efa","path":"backend/app/config.py","line_range":"7-13","gmt_create":"2026-04-23T21:00:59.64236+08:00","gmt_modified":"2026-04-23T21:00:59.64236+08:00"},{"id":"c25b39830f3b7734da975acc7f214666","path":"backend/Dockerfile","line_range":"31-33","gmt_create":"2026-04-23T21:00:59.642682+08:00","gmt_modified":"2026-04-23T21:00:59.642682+08:00"},{"id":"4c9d362ecce8e796e6f14850def049b0","path":"docker-compose.yml","line_range":"4-20","gmt_create":"2026-04-23T21:00:59.642976+08:00","gmt_modified":"2026-04-23T21:00:59.642976+08:00"},{"id":"d5827be2cfbe41c8177660ae877e93a4","path":"docker-compose.yml","line_range":"22-34","gmt_create":"2026-04-23T21:00:59.643262+08:00","gmt_modified":"2026-04-23T21:00:59.643262+08:00"},{"id":"03a65cdcfc173217d12ad8a417f8f033","path":"backend/app/main.py","line_range":"13-21","gmt_create":"2026-04-23T21:00:59.643535+08:00","gmt_modified":"2026-04-23T21:00:59.643535+08:00"},{"id":"3365fa8db33d43bab1d0a614e8af3a70","path":"backend/app/main.py","line_range":"45-47","gmt_create":"2026-04-23T21:00:59.644124+08:00","gmt_modified":"2026-04-23T21:00:59.644124+08:00"},{"id":"6f637c2b0796ec533aafb3b865c11cf0","path":"backend/app/schemas/auth.py","line_range":"1-34","gmt_create":"2026-04-23T21:00:59.646408+08:00","gmt_modified":"2026-04-23T21:00:59.646408+08:00"},{"id":"a698e13bfada239280fc9354ff9e2331","path":"backend/app/config.py","line_range":"7-8","gmt_create":"2026-04-23T21:00:59.64811+08:00","gmt_modified":"2026-04-23T21:00:59.64811+08:00"},{"id":"37bbab6e4f16db7eac6eee9d05e80e46","path":"README.md","line_range":"1-3","gmt_create":"2026-04-23T21:00:59.649625+08:00","gmt_modified":"2026-04-23T21:00:59.649625+08:00"},{"id":"63ecbf5e72a0354028b84eb531a58977","path":"frontend/package.json","line_range":"11-38","gmt_create":"2026-04-23T21:00:59.650192+08:00","gmt_modified":"2026-04-23T21:00:59.650193+08:00"},{"id":"bf363deac5ef38c8dc80c73b862e730b","path":"docker-compose.yml","line_range":"4-34","gmt_create":"2026-04-23T21:00:59.651828+08:00","gmt_modified":"2026-04-23T21:00:59.651828+08:00"},{"id":"c6e94075e5f689bfa2fe16f8cf965203","path":"tests/conftest.py","line_range":"19-50","gmt_create":"2026-04-23T21:00:59.65241+08:00","gmt_modified":"2026-04-23T21:00:59.65241+08:00"},{"id":"1a78f5574add6d07a1d7c947dba3f23d","path":"backend/alembic.ini","line_range":"115-150","gmt_create":"2026-04-23T21:00:59.652679+08:00","gmt_modified":"2026-04-23T21:00:59.652679+08:00"},{"id":"f6810849c947471a4b45d7ca01ec8c5f","path":"frontend/tailwind.config.ts","line_range":"5-9","gmt_create":"2026-04-23T21:00:59.653659+08:00","gmt_modified":"2026-04-23T21:00:59.653659+08:00"},{"id":"9f6d9941f3b93e29d714bfec7e83434c","path":"backend/app/main.py","line_range":"30-36","gmt_create":"2026-04-23T21:00:59.653983+08:00","gmt_modified":"2026-04-23T21:00:59.653984+08:00"},{"id":"669d67125dcddb0756f4ff50a43512c6","path":"backend/app/config.py","line_range":"9-13","gmt_create":"2026-04-23T21:00:59.654266+08:00","gmt_modified":"2026-04-23T21:00:59.654266+08:00"},{"id":"85792f0b1e34b5b48b0300aa606ed6e6","path":"backend/app/main.py","line_range":"1-56","gmt_create":"2026-04-23T21:02:44.159246+08:00","gmt_modified":"2026-04-23T21:02:44.159246+08:00"},{"id":"f240c1067c223a019ba05b0fbd718aa4","path":"backend/app/main.py","line_range":"1-84","gmt_create":"2026-04-24T10:58:35.335284+08:00","gmt_modified":"2026-04-24T10:58:35.335284+08:00"},{"id":"a9fb75d1fdb833a11b36bc7b298f19be","path":"frontend/lib/api.ts","line_range":"1-154","gmt_create":"2026-04-24T10:58:35.349742+08:00","gmt_modified":"2026-04-24T10:58:35.349742+08:00"},{"id":"40325db1cb621a9af027150a8c5cf8e9","path":"frontend/lib/auth.ts","line_range":"1-73","gmt_create":"2026-04-24T10:58:35.350062+08:00","gmt_modified":"2026-04-24T10:58:35.350062+08:00"},{"id":"93d8c6a312849c344b6a9713b671840f","path":"backend/requirements.txt","line_range":"1-39","gmt_create":"2026-04-24T10:58:35.35098+08:00","gmt_modified":"2026-04-24T10:58:35.35098+08:00"},{"id":"844b21a35ae39ead76ff8831eb974e5a","path":"backend/app/main.py","line_range":"81-84","gmt_create":"2026-04-24T10:58:35.352287+08:00","gmt_modified":"2026-04-24T10:58:35.352287+08:00"},{"id":"3af33bd686ce3d418e31843cac66f58b","path":"backend/README.md","line_range":"12-67","gmt_create":"2026-04-24T10:58:35.35614+08:00","gmt_modified":"2026-04-24T10:58:35.356141+08:00"},{"id":"06c6dfcd66159d42fa9b9eafd1e36a04","path":"frontend/README.md","line_range":"11-34","gmt_create":"2026-04-24T10:58:35.35673+08:00","gmt_modified":"2026-04-24T10:58:35.35673+08:00"},{"id":"903da86dc3fb26783f45f247d60e9534","path":"backend/README.md","line_range":"69-126","gmt_create":"2026-04-24T10:58:35.357072+08:00","gmt_modified":"2026-04-24T10:58:35.357072+08:00"},{"id":"0ffe337a73c8fb7254f3e48932a8ae7f","path":"backend/README.md","line_range":"209-234","gmt_create":"2026-04-24T10:58:35.357641+08:00","gmt_modified":"2026-04-24T10:58:35.357642+08:00"},{"id":"55369db351eb916a3210b22f3d672162","path":"frontend/README.md","line_range":"161-170","gmt_create":"2026-04-24T10:58:35.358984+08:00","gmt_modified":"2026-04-24T10:58:35.358984+08:00"},{"id":"6c080aba7d0e611bd4e7f268835b630f","path":"backend/app/middleware/logging_middleware.py","line_range":"1-24","gmt_create":"2026-04-24T10:58:51.060864+08:00","gmt_modified":"2026-04-24T10:58:51.060864+08:00"},{"id":"a7bba55ddc4dd5d215e881e8432d83ea","path":"backend/app/middleware/rate_limit.py","line_range":"1-83","gmt_create":"2026-04-24T10:58:51.061198+08:00","gmt_modified":"2026-04-24T10:58:51.061198+08:00"},{"id":"7c7425c51cc43b8840cefd9764b47204","path":"backend/app/api/admin.py","line_range":"1-108","gmt_create":"2026-04-24T10:58:51.061492+08:00","gmt_modified":"2026-04-24T10:58:51.061492+08:00"},{"id":"6e4a52820e780e4b42651a8214ad4493","path":"backend/app/api/reports.py","line_range":"1-75","gmt_create":"2026-04-24T10:58:51.061762+08:00","gmt_modified":"2026-04-24T10:58:51.061763+08:00"},{"id":"4247da3fc00a7e5f8b73775321eccf8e","path":"backend/app/api/subscriptions.py","line_range":"1-77","gmt_create":"2026-04-24T10:58:51.062039+08:00","gmt_modified":"2026-04-24T10:58:51.062039+08:00"},{"id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","path":"backend/app/services/admin.py","line_range":"1-188","gmt_create":"2026-04-24T10:58:51.062452+08:00","gmt_modified":"2026-04-24T10:58:51.062452+08:00"},{"id":"557281ca025f76d0dc2db67e56b44053","path":"backend/app/services/subscription.py","line_range":"1-155","gmt_create":"2026-04-24T10:58:51.062795+08:00","gmt_modified":"2026-04-24T10:58:51.062795+08:00"},{"id":"e2d4838e58acc0eee236ef586abab64e","path":"backend/app/main.py","line_range":"13-48","gmt_create":"2026-04-24T10:58:51.064016+08:00","gmt_modified":"2026-04-24T10:58:51.064016+08:00"},{"id":"8aee7654d1f435ab53d8ddaabd269fed","path":"backend/app/database.py","line_range":"6-29","gmt_create":"2026-04-24T10:58:51.06434+08:00","gmt_modified":"2026-04-24T10:58:51.06434+08:00"},{"id":"acd9e6c32084e589d5aeb1665d918dfd","path":"backend/app/api/deps.py","line_range":"13-43","gmt_create":"2026-04-24T10:58:51.064666+08:00","gmt_modified":"2026-04-24T10:58:51.064667+08:00"},{"id":"33ec8bca51cb9f667bf91088dd6b6a70","path":"backend/app/main.py","line_range":"24-48","gmt_create":"2026-04-24T10:58:51.065096+08:00","gmt_modified":"2026-04-24T10:58:51.065096+08:00"},{"id":"712424bd3bd3d5f39b1a0a72acc9952a","path":"backend/app/middleware/rate_limit.py","line_range":"10-83","gmt_create":"2026-04-24T10:58:51.065564+08:00","gmt_modified":"2026-04-24T10:58:51.065564+08:00"},{"id":"9357a0fcca02068d428f4a191d08fdcd","path":"backend/app/middleware/logging_middleware.py","line_range":"8-24","gmt_create":"2026-04-24T10:58:51.065888+08:00","gmt_modified":"2026-04-24T10:58:51.065888+08:00"},{"id":"8efcce12915471fe5b88fe058bcf238e","path":"backend/app/services/auth.py","line_range":"16-69","gmt_create":"2026-04-24T10:58:51.06648+08:00","gmt_modified":"2026-04-24T10:58:51.06648+08:00"},{"id":"7f81ebbdde3496054e6f43f5eef366dc","path":"backend/app/services/admin.py","line_range":"14-188","gmt_create":"2026-04-24T10:58:51.06683+08:00","gmt_modified":"2026-04-24T10:58:51.06683+08:00"},{"id":"f4d57f9a78585969a006b7451ea8ce84","path":"backend/app/services/subscription.py","line_range":"69-155","gmt_create":"2026-04-24T10:58:51.06716+08:00","gmt_modified":"2026-04-24T10:58:51.06716+08:00"},{"id":"608c00e1835ad72363ef08796961faca","path":"backend/app/config.py","line_range":"4-17","gmt_create":"2026-04-24T10:58:51.068971+08:00","gmt_modified":"2026-04-24T10:58:51.068971+08:00"},{"id":"ec4bf600a513dc2b014c85e141d7582d","path":"backend/app/workers/scheduler.py","line_range":"51-85","gmt_create":"2026-04-24T10:58:51.0746+08:00","gmt_modified":"2026-04-24T10:58:51.0746+08:00"},{"id":"9606b8243736b4a6f5ecfe152b2ab6dd","path":"backend/app/middleware/rate_limit.py","line_range":"34-83","gmt_create":"2026-04-24T10:58:51.079072+08:00","gmt_modified":"2026-04-24T10:58:51.079072+08:00"},{"id":"05664cbd35007caa5290760cc1ef1b99","path":"backend/app/api/admin.py","line_range":"29-108","gmt_create":"2026-04-24T10:58:51.079983+08:00","gmt_modified":"2026-04-24T10:58:51.079983+08:00"},{"id":"3d85cad939ce858f9c6d153d425c19fb","path":"backend/app/services/subscription.py","line_range":"25-155","gmt_create":"2026-04-24T10:58:51.081143+08:00","gmt_modified":"2026-04-24T10:58:51.081143+08:00"},{"id":"36769bd305cd5f664fa6e28f82e4b3e7","path":"backend/app/schemas/subscription.py","line_range":"1-41","gmt_create":"2026-04-24T10:58:51.08184+08:00","gmt_modified":"2026-04-24T10:58:51.08184+08:00"},{"id":"14c2d098319eeab16c64ff7d1447df6b","path":"backend/app/api/reports.py","line_range":"18-75","gmt_create":"2026-04-24T10:58:51.082903+08:00","gmt_modified":"2026-04-24T10:58:51.082904+08:00"},{"id":"1f8d26b6a5da49d89d95bb13c7ace2c6","path":"backend/app/models/user.py","line_range":"1-48","gmt_create":"2026-04-24T10:59:38.896976+08:00","gmt_modified":"2026-04-24T10:59:38.896976+08:00"},{"id":"c8f2dbcb7475bd189a34c7061ea46c6d","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","line_range":"1-41","gmt_create":"2026-04-24T10:59:38.901742+08:00","gmt_modified":"2026-04-24T10:59:38.901742+08:00"},{"id":"08c1475254a5bc8877ff29a895de3b6a","path":"backend/app/services/auth.py","line_range":"1-175","gmt_create":"2026-04-24T10:59:38.902658+08:00","gmt_modified":"2026-04-24T10:59:38.902658+08:00"},{"id":"f5978358d04c3c917d9ca5044c7f36fa","path":"backend/app/models/user.py","line_range":"11-48","gmt_create":"2026-04-24T10:59:38.903869+08:00","gmt_modified":"2026-04-24T10:59:38.903869+08:00"},{"id":"675ab6c1ae510ca753b5e966b7b6a10c","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","line_range":"21-41","gmt_create":"2026-04-24T10:59:38.907463+08:00","gmt_modified":"2026-04-24T10:59:38.907463+08:00"},{"id":"fe351bf59a46bec7f77ffe40a68a5993","path":"backend/app/services/auth.py","line_range":"40-56","gmt_create":"2026-04-24T10:59:38.917216+08:00","gmt_modified":"2026-04-24T10:59:38.917216+08:00"},{"id":"46e69841e5c5dc62faa55c9f066586d6","path":"backend/app/services/auth.py","line_range":"74-107","gmt_create":"2026-04-24T10:59:38.919469+08:00","gmt_modified":"2026-04-24T10:59:38.919469+08:00"},{"id":"cecc8857775f7928d465b68e429493d2","path":"backend/app/services/auth.py","line_range":"110-140","gmt_create":"2026-04-24T10:59:38.91977+08:00","gmt_modified":"2026-04-24T10:59:38.91977+08:00"},{"id":"1153d8a149a70bc79ca59a9dcba5945c","path":"backend/app/schemas/auth.py","line_range":"8-55","gmt_create":"2026-04-24T10:59:38.920046+08:00","gmt_modified":"2026-04-24T10:59:38.920046+08:00"},{"id":"35dd08df9c7a562d9c7b8edf740eaf3c","path":"backend/app/api/auth.py","line_range":"33-115","gmt_create":"2026-04-24T10:59:38.920424+08:00","gmt_modified":"2026-04-24T10:59:38.920424+08:00"},{"id":"dc735ee4a0f12140bcee122a67f4a13b","path":"frontend/components/layout/sidebar.tsx","line_range":"1-63","gmt_create":"2026-04-24T11:01:58.065941+08:00","gmt_modified":"2026-04-24T11:01:58.065941+08:00"},{"id":"f990ecd63842b3ab82f5b8c8dcde2a6b","path":"frontend/next.config.mjs","line_range":"1-5","gmt_create":"2026-04-24T11:01:58.066899+08:00","gmt_modified":"2026-04-24T11:01:58.0669+08:00"},{"id":"d5efa0fbc545b778dd913854d860c502","path":"frontend/types/next-auth.d.ts","line_range":"1-29","gmt_create":"2026-04-24T11:01:58.069351+08:00","gmt_modified":"2026-04-24T11:01:58.069351+08:00"},{"id":"46434c04e402674d97a6e2017a3a13c0","path":"backend/app/schemas/auth.py","line_range":"8-62","gmt_create":"2026-04-24T11:02:17.54295+08:00","gmt_modified":"2026-04-24T11:02:17.54295+08:00"},{"id":"3a0fd619768c80d413f8b02b3daec229","path":"backend/app/services/auth.py","line_range":"74-175","gmt_create":"2026-04-24T11:02:17.543584+08:00","gmt_modified":"2026-04-24T11:02:17.543584+08:00"},{"id":"86af0295eebcd62f33207e158db86c81","path":"backend/app/api/auth.py","line_range":"65-115","gmt_create":"2026-04-24T11:02:17.544119+08:00","gmt_modified":"2026-04-24T11:02:17.544119+08:00"},{"id":"809fc86e3ce390a1af1db1e0cd5ad787","path":"frontend/lib/api.ts","line_range":"55-84","gmt_create":"2026-04-24T11:02:17.544907+08:00","gmt_modified":"2026-04-24T11:02:17.544908+08:00"},{"id":"29ee02d164db08d7b9bd4591195e191b","path":"frontend/lib/auth.ts","line_range":"5-56","gmt_create":"2026-04-24T11:02:17.550558+08:00","gmt_modified":"2026-04-24T11:02:17.550559+08:00"},{"id":"73c4889fcacaea737921a568bf20383d","path":"frontend/lib/auth.ts","line_range":"13-32","gmt_create":"2026-04-24T11:02:17.552671+08:00","gmt_modified":"2026-04-24T11:02:17.552672+08:00"},{"id":"11c2505e56ba9a48c50be4c915f22c9d","path":"backend/app/services/auth.py","line_range":"27-37","gmt_create":"2026-04-24T11:02:17.554379+08:00","gmt_modified":"2026-04-24T11:02:17.554379+08:00"},{"id":"5f32b18b18cea3b2bdc9150366c24e5e","path":"backend/app/api/deps.py","line_range":"26-37","gmt_create":"2026-04-24T11:02:17.554832+08:00","gmt_modified":"2026-04-24T11:02:17.554832+08:00"},{"id":"c4abaa8a82ad75d09ee66f97fbad4b96","path":"backend/app/config.py","line_range":"9-10","gmt_create":"2026-04-24T11:02:17.555347+08:00","gmt_modified":"2026-04-24T11:02:17.555347+08:00"},{"id":"08ac91fb508b386f0e6c66e53b03a471","path":"backend/app/schemas/auth.py","line_range":"8-11","gmt_create":"2026-04-24T11:02:17.556938+08:00","gmt_modified":"2026-04-24T11:02:17.556938+08:00"},{"id":"d4ea500c0acb4ebf267a44908e23f787","path":"backend/app/services/auth.py","line_range":"40-55","gmt_create":"2026-04-24T11:02:17.557577+08:00","gmt_modified":"2026-04-24T11:02:17.557577+08:00"},{"id":"b4f0bea37f71296167571d8831ebe6d5","path":"tests/test_auth.py","line_range":"25-58","gmt_create":"2026-04-24T11:02:17.558569+08:00","gmt_modified":"2026-04-24T11:02:17.558569+08:00"},{"id":"46f7431da5eb82bbd7686a71abaddf78","path":"backend/app/api/auth.py","line_range":"42-57","gmt_create":"2026-04-24T11:02:17.558961+08:00","gmt_modified":"2026-04-24T11:02:17.558961+08:00"},{"id":"0ba2ea54873608360c48c8b5aaeea20f","path":"backend/app/services/auth.py","line_range":"58-71","gmt_create":"2026-04-24T11:02:17.559312+08:00","gmt_modified":"2026-04-24T11:02:17.559312+08:00"},{"id":"2d170933ae8c838199f6d68a2b9165c0","path":"tests/test_auth.py","line_range":"61-84","gmt_create":"2026-04-24T11:02:17.560326+08:00","gmt_modified":"2026-04-24T11:02:17.560327+08:00"},{"id":"0ea85b56099b9087bd22eec96b7bb752","path":"backend/app/services/auth.py","line_range":"74-140","gmt_create":"2026-04-24T11:02:17.560916+08:00","gmt_modified":"2026-04-24T11:02:17.560916+08:00"},{"id":"2a4087b6941ca17dd651147f2f23451c","path":"backend/app/api/auth.py","line_range":"65-90","gmt_create":"2026-04-24T11:02:17.561945+08:00","gmt_modified":"2026-04-24T11:02:17.561945+08:00"},{"id":"88c12e200d5c3ea53c695aa4209cecd9","path":"backend/app/api/auth.py","line_range":"65-76","gmt_create":"2026-04-24T11:02:17.562602+08:00","gmt_modified":"2026-04-24T11:02:17.562603+08:00"},{"id":"42b92d878423a23067e9a6da104e3a5e","path":"backend/app/api/auth.py","line_range":"79-90","gmt_create":"2026-04-24T11:02:17.564153+08:00","gmt_modified":"2026-04-24T11:02:17.564153+08:00"},{"id":"abadc99952ad6e00ab4bfb66b84732bb","path":"backend/app/schemas/auth.py","line_range":"33-41","gmt_create":"2026-04-24T11:02:17.56603+08:00","gmt_modified":"2026-04-24T11:02:17.56603+08:00"},{"id":"f784a33e47128515d518555d99103f62","path":"backend/app/services/auth.py","line_range":"143-175","gmt_create":"2026-04-24T11:02:17.566806+08:00","gmt_modified":"2026-04-24T11:02:17.566806+08:00"},{"id":"173f8de5896e18fc81cdd5d72e2a8c07","path":"backend/app/api/auth.py","line_range":"93-115","gmt_create":"2026-04-24T11:02:17.567894+08:00","gmt_modified":"2026-04-24T11:02:17.567894+08:00"},{"id":"3ab144009e705151f69698d2d8a81cea","path":"backend/app/services/auth.py","line_range":"35-37","gmt_create":"2026-04-24T11:02:17.56892+08:00","gmt_modified":"2026-04-24T11:02:17.56892+08:00"},{"id":"570a917d85850ab1208fce5823b110a3","path":"backend/app/api/auth.py","line_range":"60-62","gmt_create":"2026-04-24T11:02:17.569617+08:00","gmt_modified":"2026-04-24T11:02:17.569617+08:00"},{"id":"f92c0c41197c488f04f994bf0f7ea465","path":"tests/test_auth.py","line_range":"87-104","gmt_create":"2026-04-24T11:02:17.570008+08:00","gmt_modified":"2026-04-24T11:02:17.570008+08:00"},{"id":"5688471e2418628ac2a6409451708d06","path":"backend/app/api/auth.py","line_range":"1-115","gmt_create":"2026-04-24T11:02:17.571751+08:00","gmt_modified":"2026-04-24T11:02:17.571751+08:00"},{"id":"7075cde1c771c46dbbd37b3c09dac53d","path":"backend/app/api/deps.py","line_range":"20-41","gmt_create":"2026-04-24T11:02:17.576276+08:00","gmt_modified":"2026-04-24T11:02:17.576276+08:00"},{"id":"607e99e751640281d26516c772548b93","path":"frontend/lib/api.ts","line_range":"17-39","gmt_create":"2026-04-24T11:02:17.576883+08:00","gmt_modified":"2026-04-24T11:02:17.576883+08:00"},{"id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","path":"backend/app/main.py","line_range":"12-78","gmt_create":"2026-04-24T11:02:30.018464+08:00","gmt_modified":"2026-04-24T11:02:30.018464+08:00"},{"id":"10d3948b1394ffa0110796edfa0bfc25","path":"backend/app/api/auth.py","line_range":"30","gmt_create":"2026-04-24T11:02:30.018782+08:00","gmt_modified":"2026-04-24T11:02:30.018782+08:00"},{"id":"3c41910bad9855635d1362efc314463a","path":"backend/app/api/reports.py","line_range":"15","gmt_create":"2026-04-24T11:02:30.019676+08:00","gmt_modified":"2026-04-24T11:02:30.019676+08:00"},{"id":"f32e078c985967af30d2c526290d9acb","path":"backend/app/api/subscriptions.py","line_range":"23","gmt_create":"2026-04-24T11:02:30.020008+08:00","gmt_modified":"2026-04-24T11:02:30.020008+08:00"},{"id":"c10a89cdd47474f51664a239b82cc2e2","path":"backend/app/api/admin.py","line_range":"17","gmt_create":"2026-04-24T11:02:30.020325+08:00","gmt_modified":"2026-04-24T11:02:30.020326+08:00"},{"id":"d6ebce8c7d9e9de127486400670ebed0","path":"backend/app/main.py","line_range":"39-84","gmt_create":"2026-04-24T11:02:30.020913+08:00","gmt_modified":"2026-04-24T11:02:30.020913+08:00"},{"id":"ec3ed02cad3cd8af4bacb5c978273092","path":"backend/app/api/subscriptions.py","line_range":"26-77","gmt_create":"2026-04-24T11:02:30.021508+08:00","gmt_modified":"2026-04-24T11:02:30.021509+08:00"},{"id":"2db9940a42c91fc92f23595491ea93d1","path":"backend/app/main.py","line_range":"67-78","gmt_create":"2026-04-24T11:02:30.022384+08:00","gmt_modified":"2026-04-24T11:02:30.022384+08:00"},{"id":"68fbb2bd365f96a98ea187a9738c4460","path":"backend/app/api/auth.py","line_range":"33-57","gmt_create":"2026-04-24T11:02:30.024114+08:00","gmt_modified":"2026-04-24T11:02:30.024114+08:00"},{"id":"44f9c9f195e096efbd6c6a6f97880944","path":"backend/app/api/reports.py","line_range":"51-75","gmt_create":"2026-04-24T11:02:30.02932+08:00","gmt_modified":"2026-04-24T11:02:30.02932+08:00"},{"id":"cbe8ffc1cfb98ac79c7659e968191837","path":"backend/app/services/citation.py","line_range":"343-466","gmt_create":"2026-04-24T11:02:30.029647+08:00","gmt_modified":"2026-04-24T11:02:30.029647+08:00"},{"id":"97f9b6149bd43feb0f69cf2582ab6305","path":"backend/app/services/subscription.py","line_range":"85-117","gmt_create":"2026-04-24T11:02:30.030707+08:00","gmt_modified":"2026-04-24T11:02:30.030707+08:00"},{"id":"ce4de96353f8f81ca825173ddbec1150","path":"backend/app/schemas/subscription.py","line_range":"12-41","gmt_create":"2026-04-24T11:02:30.031384+08:00","gmt_modified":"2026-04-24T11:02:30.031384+08:00"},{"id":"a87a1a7c1723518159d5818c197996cc","path":"backend/app/services/subscription.py","line_range":"56-155","gmt_create":"2026-04-24T11:02:30.031685+08:00","gmt_modified":"2026-04-24T11:02:30.031686+08:00"},{"id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","path":"backend/app/api/admin.py","line_range":"29-45","gmt_create":"2026-04-24T11:02:30.031966+08:00","gmt_modified":"2026-04-24T11:02:30.031966+08:00"},{"id":"f7314a4515e822cba6f37d7a8f1970f3","path":"backend/app/services/admin.py","line_range":"14-46","gmt_create":"2026-04-24T11:02:30.032241+08:00","gmt_modified":"2026-04-24T11:02:30.032242+08:00"},{"id":"ef31f4aa4fbd1b6ff76eba467b757a04","path":"backend/app/middleware/rate_limit.py","line_range":"34-69","gmt_create":"2026-04-24T11:02:30.033139+08:00","gmt_modified":"2026-04-24T11:02:30.03314+08:00"},{"id":"3a7201f4564dbcf35c5771f1b5d58cb6","path":"backend/app/api/auth.py","line_range":"46-50","gmt_create":"2026-04-24T11:02:30.037193+08:00","gmt_modified":"2026-04-24T11:02:30.037193+08:00"},{"id":"39c3dbe67ab2ae74446fe6a118bd8738","path":"backend/app/api/reports.py","line_range":"25-29","gmt_create":"2026-04-24T11:02:30.038125+08:00","gmt_modified":"2026-04-24T11:02:30.038125+08:00"},{"id":"68d937267aab2509edc0c7b67e1b5ef6","path":"backend/app/api/subscriptions.py","line_range":"53-57","gmt_create":"2026-04-24T11:02:30.038578+08:00","gmt_modified":"2026-04-24T11:02:30.038578+08:00"},{"id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","path":"backend/app/api/admin.py","line_range":"22-25","gmt_create":"2026-04-24T11:02:30.038936+08:00","gmt_modified":"2026-04-24T11:02:30.038936+08:00"},{"id":"a9c1b0716ae36af22fce6148c2e40ce5","path":"backend/app/middleware/rate_limit.py","line_range":"47-49","gmt_create":"2026-04-24T11:02:30.039285+08:00","gmt_modified":"2026-04-24T11:02:30.039285+08:00"}],"knowledge_relations":[{"id":34,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e 1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","gmt_create":"2026-04-22T19:25:18.934991+08:00","gmt_modified":"2026-04-22T19:25:18.934991+08:00"},{"id":35,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"26f80935-eac2-44ee-bcdb-d6a79c537750","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e 26f80935-eac2-44ee-bcdb-d6a79c537750","gmt_create":"2026-04-22T19:25:18.935426+08:00","gmt_modified":"2026-04-22T19:25:18.935426+08:00"},{"id":36,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"eb1288f7-5ea1-413a-8f54-4f870306d14d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e eb1288f7-5ea1-413a-8f54-4f870306d14d","gmt_create":"2026-04-22T19:25:18.935875+08:00","gmt_modified":"2026-04-22T19:25:18.935875+08:00"},{"id":37,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","gmt_create":"2026-04-22T19:25:18.936315+08:00","gmt_modified":"2026-04-22T19:25:18.936316+08:00"},{"id":45,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"d2c7157d-157f-4990-8f76-11f3ea5435f7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e d2c7157d-157f-4990-8f76-11f3ea5435f7","gmt_create":"2026-04-22T19:25:18.939978+08:00","gmt_modified":"2026-04-22T19:25:18.939978+08:00"},{"id":46,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e1e0bd0e-01b3-4543-9781-d9beb32b9a57","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e e1e0bd0e-01b3-4543-9781-d9beb32b9a57","gmt_create":"2026-04-22T19:25:18.940415+08:00","gmt_modified":"2026-04-22T19:25:18.940415+08:00"},{"id":47,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e9a02c86-236b-49cb-bbed-9462ee123c04","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e e9a02c86-236b-49cb-bbed-9462ee123c04","gmt_create":"2026-04-22T19:25:18.941227+08:00","gmt_modified":"2026-04-22T19:25:18.941227+08:00"},{"id":48,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-23T15:19:43.777831+08:00","gmt_modified":"2026-04-23T15:19:43.777831+08:00"},{"id":49,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-04-23T15:19:43.778774+08:00","gmt_modified":"2026-04-23T15:19:43.778774+08:00"},{"id":50,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"eca13a610badfc5ffc6210827fb96991","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/header.tsx","gmt_create":"2026-04-23T15:19:43.779153+08:00","gmt_modified":"2026-04-23T15:19:43.779154+08:00"},{"id":51,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"18a0651d895fba9bb4e0c0229459efdc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/sidebar.tsx","gmt_create":"2026-04-23T15:19:43.779524+08:00","gmt_modified":"2026-04-23T15:19:43.779524+08:00"},{"id":52,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-23T15:19:43.779869+08:00","gmt_modified":"2026-04-23T15:19:43.779869+08:00"},{"id":53,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/table.tsx","gmt_create":"2026-04-23T15:19:43.780775+08:00","gmt_modified":"2026-04-23T15:19:43.780775+08:00"},{"id":54,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"108b0c4b4dcfb6aa39a5eb138225c148","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dialog.tsx","gmt_create":"2026-04-23T15:19:43.781767+08:00","gmt_modified":"2026-04-23T15:19:43.781767+08:00"},{"id":55,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T15:19:43.782177+08:00","gmt_modified":"2026-04-23T15:19:43.782177+08:00"},{"id":56,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"f93ae024fe0a2e69698037dff6df205f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/utils.ts","gmt_create":"2026-04-23T15:19:43.782527+08:00","gmt_modified":"2026-04-23T15:19:43.782527+08:00"},{"id":57,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"d5f2266643d2011c66e86af088ec637f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/trend-chart.tsx","gmt_create":"2026-04-23T15:19:43.782861+08:00","gmt_modified":"2026-04-23T15:19:43.782861+08:00"},{"id":58,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"f1a7d61831cc0a45ac6220294f15c21d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-23T15:19:43.783164+08:00","gmt_modified":"2026-04-23T15:19:43.783165+08:00"},{"id":59,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-23T15:19:43.783668+08:00","gmt_modified":"2026-04-23T15:19:43.783668+08:00"},{"id":60,"source_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T15:19:43.783987+08:00","gmt_modified":"2026-04-23T15:19:43.783987+08:00"},{"id":61,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3bd4eedea376e3a3d9f9fbff4fe27a65","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/sidebar.tsx#1-54","gmt_create":"2026-04-23T15:19:43.784455+08:00","gmt_modified":"2026-04-23T15:19:43.784455+08:00"},{"id":62,"source_id":"18a0651d895fba9bb4e0c0229459efdc","target_id":"3bd4eedea376e3a3d9f9fbff4fe27a65","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-54","gmt_create":"2026-04-23T15:19:43.784807+08:00","gmt_modified":"2026-04-23T15:19:43.784807+08:00"},{"id":63,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/header.tsx#1-30","gmt_create":"2026-04-23T15:19:43.785303+08:00","gmt_modified":"2026-04-23T15:19:43.785303+08:00"},{"id":64,"source_id":"eca13a610badfc5ffc6210827fb96991","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-30","gmt_create":"2026-04-23T15:19:43.785622+08:00","gmt_modified":"2026-04-23T15:19:43.785622+08:00"},{"id":65,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#1-118","gmt_create":"2026-04-23T15:19:43.78727+08:00","gmt_modified":"2026-04-23T15:19:43.787271+08:00"},{"id":66,"source_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-118","gmt_create":"2026-04-23T15:19:43.788224+08:00","gmt_modified":"2026-04-23T15:19:43.788224+08:00"},{"id":67,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#1-123","gmt_create":"2026-04-23T15:19:43.789533+08:00","gmt_modified":"2026-04-23T15:19:43.789533+08:00"},{"id":68,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:19:43.790255+08:00","gmt_modified":"2026-04-23T15:19:43.790255+08:00"},{"id":69,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"b7796fc6197ecce5beb461b9466e54a0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/trend-chart.tsx#1-60","gmt_create":"2026-04-23T15:19:43.790795+08:00","gmt_modified":"2026-04-23T15:19:43.790795+08:00"},{"id":70,"source_id":"d5f2266643d2011c66e86af088ec637f","target_id":"b7796fc6197ecce5beb461b9466e54a0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-60","gmt_create":"2026-04-23T15:19:43.791134+08:00","gmt_modified":"2026-04-23T15:19:43.791134+08:00"},{"id":71,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/platform-chart.tsx#1-68","gmt_create":"2026-04-23T15:19:43.791601+08:00","gmt_modified":"2026-04-23T15:19:43.791601+08:00"},{"id":72,"source_id":"f1a7d61831cc0a45ac6220294f15c21d","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-68","gmt_create":"2026-04-23T15:19:43.791902+08:00","gmt_modified":"2026-04-23T15:19:43.791902+08:00"},{"id":73,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-18","gmt_create":"2026-04-23T15:19:43.792356+08:00","gmt_modified":"2026-04-23T15:19:43.792356+08:00"},{"id":74,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-18","gmt_create":"2026-04-23T15:19:43.79267+08:00","gmt_modified":"2026-04-23T15:19:43.79267+08:00"},{"id":75,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#1-7","gmt_create":"2026-04-23T15:19:43.79312+08:00","gmt_modified":"2026-04-23T15:19:43.79312+08:00"},{"id":76,"source_id":"f93ae024fe0a2e69698037dff6df205f","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-7","gmt_create":"2026-04-23T15:19:43.793455+08:00","gmt_modified":"2026-04-23T15:19:43.793455+08:00"},{"id":77,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0f87c8089f548883d056f0a0d79e273f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-79","gmt_create":"2026-04-23T15:19:43.793866+08:00","gmt_modified":"2026-04-23T15:19:43.793866+08:00"},{"id":78,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"0f87c8089f548883d056f0a0d79e273f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-79","gmt_create":"2026-04-23T15:19:43.794158+08:00","gmt_modified":"2026-04-23T15:19:43.794158+08:00"},{"id":79,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"9beee1f41fe8f0750fd97155f9d54bbb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#67-70","gmt_create":"2026-04-23T15:19:43.797877+08:00","gmt_modified":"2026-04-23T15:19:43.797877+08:00"},{"id":80,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"9beee1f41fe8f0750fd97155f9d54bbb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-70","gmt_create":"2026-04-23T15:19:43.798244+08:00","gmt_modified":"2026-04-23T15:19:43.798244+08:00"},{"id":81,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"8fe2e22a963442076e1ce16ab777573c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#56-66","gmt_create":"2026-04-23T15:19:43.799319+08:00","gmt_modified":"2026-04-23T15:19:43.799319+08:00"},{"id":82,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"8fe2e22a963442076e1ce16ab777573c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-66","gmt_create":"2026-04-23T15:19:43.799625+08:00","gmt_modified":"2026-04-23T15:19:43.799625+08:00"},{"id":83,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3124ad882ca2cf8fecb6b93696c7f233","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#72-77","gmt_create":"2026-04-23T15:19:43.801555+08:00","gmt_modified":"2026-04-23T15:19:43.801555+08:00"},{"id":84,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"3124ad882ca2cf8fecb6b93696c7f233","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-77","gmt_create":"2026-04-23T15:19:43.801939+08:00","gmt_modified":"2026-04-23T15:19:43.801939+08:00"},{"id":85,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"17a97b4ac37fb67b8eda7ce2887c38e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#17-20","gmt_create":"2026-04-23T15:19:43.806186+08:00","gmt_modified":"2026-04-23T15:19:43.806186+08:00"},{"id":86,"source_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","target_id":"17a97b4ac37fb67b8eda7ce2887c38e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-20","gmt_create":"2026-04-23T15:19:43.80664+08:00","gmt_modified":"2026-04-23T15:19:43.80664+08:00"},{"id":87,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"84cba1e0d516e8c9859402fd5c1bc83c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#3-40","gmt_create":"2026-04-23T15:19:43.815637+08:00","gmt_modified":"2026-04-23T15:19:43.815637+08:00"},{"id":88,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"84cba1e0d516e8c9859402fd5c1bc83c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-40","gmt_create":"2026-04-23T15:19:43.817147+08:00","gmt_modified":"2026-04-23T15:19:43.817147+08:00"},{"id":107,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"b55a164add5a8fec2ef0e489f7234829","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-47","gmt_create":"2026-04-23T15:19:45.617445+08:00","gmt_modified":"2026-04-23T15:19:45.617445+08:00"},{"id":109,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"16d619435094a63740357cd6317b52cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10","gmt_create":"2026-04-23T15:19:45.618177+08:00","gmt_modified":"2026-04-23T15:19:45.618177+08:00"},{"id":111,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"fa1ee5e3822128a37e9d03af74083392","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12","gmt_create":"2026-04-23T15:19:45.619215+08:00","gmt_modified":"2026-04-23T15:19:45.619215+08:00"},{"id":113,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"7e908f05baccdfcf7f4a3ef3c9cd5c38","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21","gmt_create":"2026-04-23T15:19:45.620246+08:00","gmt_modified":"2026-04-23T15:19:45.620246+08:00"},{"id":115,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"ffe6df344be81bde3941ad8f0d77910b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13","gmt_create":"2026-04-23T15:19:45.623067+08:00","gmt_modified":"2026-04-23T15:19:45.623067+08:00"},{"id":117,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"c71fb14f8866e34c679c94a4e2432bc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13","gmt_create":"2026-04-23T15:19:45.624846+08:00","gmt_modified":"2026-04-23T15:19:45.624846+08:00"},{"id":119,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"3c68f1581d2fd6aa845dd71111a9aa9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:19:45.625985+08:00","gmt_modified":"2026-04-23T15:19:45.625985+08:00"},{"id":121,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"39afb05755a93800fd685af7274110cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-57","gmt_create":"2026-04-23T15:19:45.626917+08:00","gmt_modified":"2026-04-23T15:19:45.626917+08:00"},{"id":123,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"87a177f17800991e1ed1fb7be03abdb2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-42","gmt_create":"2026-04-23T15:19:45.627772+08:00","gmt_modified":"2026-04-23T15:19:45.627772+08:00"},{"id":125,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"ae9de874df4a46f4197b6c157c25ec6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-85","gmt_create":"2026-04-23T15:19:45.628538+08:00","gmt_modified":"2026-04-23T15:19:45.628538+08:00"},{"id":127,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-77","gmt_create":"2026-04-23T15:19:45.629465+08:00","gmt_modified":"2026-04-23T15:19:45.629465+08:00"},{"id":129,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"177c73dc4e71186d9eaa1157fc0fe97f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-46","gmt_create":"2026-04-23T15:19:45.630333+08:00","gmt_modified":"2026-04-23T15:19:45.630333+08:00"},{"id":131,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"a0be0cbddb559575861620b5b7579634","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-51","gmt_create":"2026-04-23T15:19:45.631178+08:00","gmt_modified":"2026-04-23T15:19:45.631178+08:00"},{"id":133,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"bcdf50f6234651cb9863ab210e6473e5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-42","gmt_create":"2026-04-23T15:19:45.632177+08:00","gmt_modified":"2026-04-23T15:19:45.632177+08:00"},{"id":135,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"6df0277c2486b148fa26c2682dbdaa4c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-68","gmt_create":"2026-04-23T15:19:45.63307+08:00","gmt_modified":"2026-04-23T15:19:45.63307+08:00"},{"id":137,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"5ea5f192d580031ffe57e1582b70c67e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-123","gmt_create":"2026-04-23T15:19:45.633929+08:00","gmt_modified":"2026-04-23T15:19:45.633929+08:00"},{"id":139,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"fe4a793f16cd4e12b56253c0a6d53ae0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-359","gmt_create":"2026-04-23T15:19:45.634775+08:00","gmt_modified":"2026-04-23T15:19:45.634775+08:00"},{"id":141,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"9552bd8a528207f18e4f3a1696f26a55","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-37","gmt_create":"2026-04-23T15:19:45.635763+08:00","gmt_modified":"2026-04-23T15:19:45.635763+08:00"},{"id":143,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-34","gmt_create":"2026-04-23T15:19:45.639659+08:00","gmt_modified":"2026-04-23T15:19:45.63966+08:00"},{"id":145,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-81","gmt_create":"2026-04-23T15:19:45.641965+08:00","gmt_modified":"2026-04-23T15:19:45.641965+08:00"},{"id":147,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"69118807690ef351a9de910414d5e676","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-94","gmt_create":"2026-04-23T15:19:45.643362+08:00","gmt_modified":"2026-04-23T15:19:45.643362+08:00"},{"id":149,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-77","gmt_create":"2026-04-23T15:19:45.644457+08:00","gmt_modified":"2026-04-23T15:19:45.644457+08:00"},{"id":151,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"b0777c7da17be89abb333c81c0dcf349","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 204-261","gmt_create":"2026-04-23T15:19:45.645243+08:00","gmt_modified":"2026-04-23T15:19:45.645243+08:00"},{"id":153,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-50","gmt_create":"2026-04-23T15:19:45.646445+08:00","gmt_modified":"2026-04-23T15:19:45.646445+08:00"},{"id":155,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dbf5f8a57778cf6363e834081f3d771c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 327-359","gmt_create":"2026-04-23T15:19:45.647935+08:00","gmt_modified":"2026-04-23T15:19:45.647935+08:00"},{"id":157,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-41","gmt_create":"2026-04-23T15:19:45.649807+08:00","gmt_modified":"2026-04-23T15:19:45.649807+08:00"},{"id":159,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-55","gmt_create":"2026-04-23T15:19:45.650642+08:00","gmt_modified":"2026-04-23T15:19:45.650642+08:00"},{"id":161,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-42","gmt_create":"2026-04-23T15:19:45.651529+08:00","gmt_modified":"2026-04-23T15:19:45.651529+08:00"},{"id":163,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"b84f46f058847733347974841f613688","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-39","gmt_create":"2026-04-23T15:19:45.65251+08:00","gmt_modified":"2026-04-23T15:19:45.65251+08:00"},{"id":165,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"1a2657244414b5681afded9565a86422","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-40","gmt_create":"2026-04-23T15:19:45.655814+08:00","gmt_modified":"2026-04-23T15:19:45.655814+08:00"},{"id":167,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 43-48","gmt_create":"2026-04-23T15:19:45.657941+08:00","gmt_modified":"2026-04-23T15:19:45.657942+08:00"},{"id":169,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"27a5e2dd1d197b2e3a45be41c57a6183","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35","gmt_create":"2026-04-23T15:19:45.658966+08:00","gmt_modified":"2026-04-23T15:19:45.658966+08:00"},{"id":171,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"c43e8fc0c04c5ed2db7798d99c8c77b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34","gmt_create":"2026-04-23T15:19:45.659763+08:00","gmt_modified":"2026-04-23T15:19:45.659763+08:00"},{"id":173,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"8868ab86034eecf40e80347ef8cbdebd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-30","gmt_create":"2026-04-23T15:19:45.660491+08:00","gmt_modified":"2026-04-23T15:19:45.660491+08:00"},{"id":175,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"a50f983ec39bac67dff5df80f6dad837","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-60","gmt_create":"2026-04-23T15:19:45.661271+08:00","gmt_modified":"2026-04-23T15:19:45.661271+08:00"},{"id":177,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-71","gmt_create":"2026-04-23T15:19:45.662055+08:00","gmt_modified":"2026-04-23T15:19:45.662055+08:00"},{"id":179,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"6ef6d32f97d7b50b7a4da541137423c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-27","gmt_create":"2026-04-23T15:19:45.662999+08:00","gmt_modified":"2026-04-23T15:19:45.662999+08:00"},{"id":180,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T15:20:08.989793+08:00","gmt_modified":"2026-04-23T15:20:08.989793+08:00"},{"id":181,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T15:20:08.990186+08:00","gmt_modified":"2026-04-23T15:20:08.990186+08:00"},{"id":182,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T15:20:08.990539+08:00","gmt_modified":"2026-04-23T15:20:08.990539+08:00"},{"id":183,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T15:20:08.990851+08:00","gmt_modified":"2026-04-23T15:20:08.990851+08:00"},{"id":184,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T15:20:08.991166+08:00","gmt_modified":"2026-04-23T15:20:08.991166+08:00"},{"id":185,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T15:20:08.991471+08:00","gmt_modified":"2026-04-23T15:20:08.991472+08:00"},{"id":186,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T15:20:08.991772+08:00","gmt_modified":"2026-04-23T15:20:08.991772+08:00"},{"id":187,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T15:20:08.992186+08:00","gmt_modified":"2026-04-23T15:20:08.992186+08:00"},{"id":188,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T15:20:08.992542+08:00","gmt_modified":"2026-04-23T15:20:08.992542+08:00"},{"id":189,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T15:20:08.992879+08:00","gmt_modified":"2026-04-23T15:20:08.992879+08:00"},{"id":190,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T15:20:08.997487+08:00","gmt_modified":"2026-04-23T15:20:08.997487+08:00"},{"id":191,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T15:20:08.998695+08:00","gmt_modified":"2026-04-23T15:20:08.998696+08:00"},{"id":192,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T15:20:08.999402+08:00","gmt_modified":"2026-04-23T15:20:08.999402+08:00"},{"id":193,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-04-23T15:20:09.000067+08:00","gmt_modified":"2026-04-23T15:20:09.000067+08:00"},{"id":194,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-04-23T15:20:09.000413+08:00","gmt_modified":"2026-04-23T15:20:09.000413+08:00"},{"id":195,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T15:20:09.000893+08:00","gmt_modified":"2026-04-23T15:20:09.000893+08:00"},{"id":196,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-22","gmt_create":"2026-04-23T15:20:09.00176+08:00","gmt_modified":"2026-04-23T15:20:09.00176+08:00"},{"id":197,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T15:20:09.003004+08:00","gmt_modified":"2026-04-23T15:20:09.003004+08:00"},{"id":198,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-95","gmt_create":"2026-04-23T15:20:09.003771+08:00","gmt_modified":"2026-04-23T15:20:09.003771+08:00"},{"id":199,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T15:20:09.005186+08:00","gmt_modified":"2026-04-23T15:20:09.005186+08:00"},{"id":200,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-309","gmt_create":"2026-04-23T15:20:09.00622+08:00","gmt_modified":"2026-04-23T15:20:09.00622+08:00"},{"id":201,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T15:20:09.006997+08:00","gmt_modified":"2026-04-23T15:20:09.006997+08:00"},{"id":202,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T15:20:09.007995+08:00","gmt_modified":"2026-04-23T15:20:09.007995+08:00"},{"id":203,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T15:20:09.009222+08:00","gmt_modified":"2026-04-23T15:20:09.009222+08:00"},{"id":204,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T15:20:09.010245+08:00","gmt_modified":"2026-04-23T15:20:09.010245+08:00"},{"id":205,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-130","gmt_create":"2026-04-23T15:20:09.011044+08:00","gmt_modified":"2026-04-23T15:20:09.011044+08:00"},{"id":206,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T15:20:09.012195+08:00","gmt_modified":"2026-04-23T15:20:09.012195+08:00"},{"id":207,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-04-23T15:20:09.01291+08:00","gmt_modified":"2026-04-23T15:20:09.012911+08:00"},{"id":208,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T15:20:09.013886+08:00","gmt_modified":"2026-04-23T15:20:09.013886+08:00"},{"id":209,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-18","gmt_create":"2026-04-23T15:20:09.014746+08:00","gmt_modified":"2026-04-23T15:20:09.014746+08:00"},{"id":210,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T15:20:09.015594+08:00","gmt_modified":"2026-04-23T15:20:09.015594+08:00"},{"id":211,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-206","gmt_create":"2026-04-23T15:20:09.016313+08:00","gmt_modified":"2026-04-23T15:20:09.016313+08:00"},{"id":212,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T15:20:09.017693+08:00","gmt_modified":"2026-04-23T15:20:09.017693+08:00"},{"id":213,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-205","gmt_create":"2026-04-23T15:20:09.018896+08:00","gmt_modified":"2026-04-23T15:20:09.018896+08:00"},{"id":214,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#30-90","gmt_create":"2026-04-23T15:20:09.025147+08:00","gmt_modified":"2026-04-23T15:20:09.025147+08:00"},{"id":215,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-90","gmt_create":"2026-04-23T15:20:09.02579+08:00","gmt_modified":"2026-04-23T15:20:09.02579+08:00"},{"id":216,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"91bda120c0ab69e0e7103a1c89c82424","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#95-172","gmt_create":"2026-04-23T15:20:09.026853+08:00","gmt_modified":"2026-04-23T15:20:09.026853+08:00"},{"id":217,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"91bda120c0ab69e0e7103a1c89c82424","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 95-172","gmt_create":"2026-04-23T15:20:09.027566+08:00","gmt_modified":"2026-04-23T15:20:09.027566+08:00"},{"id":218,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T15:20:09.028202+08:00","gmt_modified":"2026-04-23T15:20:09.028202+08:00"},{"id":219,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 159-234","gmt_create":"2026-04-23T15:20:09.028744+08:00","gmt_modified":"2026-04-23T15:20:09.028744+08:00"},{"id":220,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"6712051c987e10a7c26b089063367398","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#24-31","gmt_create":"2026-04-23T15:20:09.029494+08:00","gmt_modified":"2026-04-23T15:20:09.029494+08:00"},{"id":221,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"6712051c987e10a7c26b089063367398","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-31","gmt_create":"2026-04-23T15:20:09.030084+08:00","gmt_modified":"2026-04-23T15:20:09.030084+08:00"},{"id":222,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#24-32","gmt_create":"2026-04-23T15:20:09.030828+08:00","gmt_modified":"2026-04-23T15:20:09.030828+08:00"},{"id":223,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-32","gmt_create":"2026-04-23T15:20:09.031632+08:00","gmt_modified":"2026-04-23T15:20:09.031632+08:00"},{"id":224,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"06ed912983db33bb8aca162fed68282b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#24-29","gmt_create":"2026-04-23T15:20:09.032417+08:00","gmt_modified":"2026-04-23T15:20:09.032417+08:00"},{"id":225,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"06ed912983db33bb8aca162fed68282b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-29","gmt_create":"2026-04-23T15:20:09.032976+08:00","gmt_modified":"2026-04-23T15:20:09.032976+08:00"},{"id":226,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-120","gmt_create":"2026-04-23T15:20:09.037331+08:00","gmt_modified":"2026-04-23T15:20:09.037331+08:00"},{"id":227,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-120","gmt_create":"2026-04-23T15:20:09.038413+08:00","gmt_modified":"2026-04-23T15:20:09.038413+08:00"},{"id":228,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"40d0b169aad65c8bb38077deb052fc72","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-125","gmt_create":"2026-04-23T15:20:09.040261+08:00","gmt_modified":"2026-04-23T15:20:09.040261+08:00"},{"id":229,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"40d0b169aad65c8bb38077deb052fc72","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-125","gmt_create":"2026-04-23T15:20:09.04098+08:00","gmt_modified":"2026-04-23T15:20:09.04098+08:00"},{"id":230,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"8b5af998852596e1e08b0e0216bc4b93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-124","gmt_create":"2026-04-23T15:20:09.041526+08:00","gmt_modified":"2026-04-23T15:20:09.041526+08:00"},{"id":231,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"8b5af998852596e1e08b0e0216bc4b93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-124","gmt_create":"2026-04-23T15:20:09.041834+08:00","gmt_modified":"2026-04-23T15:20:09.041834+08:00"},{"id":232,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T15:20:09.04598+08:00","gmt_modified":"2026-04-23T15:20:09.04598+08:00"},{"id":233,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-86","gmt_create":"2026-04-23T15:20:09.046352+08:00","gmt_modified":"2026-04-23T15:20:09.046352+08:00"},{"id":234,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#42-90","gmt_create":"2026-04-23T15:20:09.050041+08:00","gmt_modified":"2026-04-23T15:20:09.050041+08:00"},{"id":235,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-90","gmt_create":"2026-04-23T15:20:09.050351+08:00","gmt_modified":"2026-04-23T15:20:09.050351+08:00"},{"id":236,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e79301a4bc26aa6b49f3f52c3182c3f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#175-234","gmt_create":"2026-04-23T15:20:09.051815+08:00","gmt_modified":"2026-04-23T15:20:09.051815+08:00"},{"id":237,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"e79301a4bc26aa6b49f3f52c3182c3f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 175-234","gmt_create":"2026-04-23T15:20:09.052165+08:00","gmt_modified":"2026-04-23T15:20:09.052166+08:00"},{"id":238,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-48","gmt_create":"2026-04-23T15:20:09.052615+08:00","gmt_modified":"2026-04-23T15:20:09.052615+08:00"},{"id":239,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-48","gmt_create":"2026-04-23T15:20:09.052947+08:00","gmt_modified":"2026-04-23T15:20:09.052947+08:00"},{"id":240,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-48","gmt_create":"2026-04-23T15:20:09.053449+08:00","gmt_modified":"2026-04-23T15:20:09.053449+08:00"},{"id":241,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-48","gmt_create":"2026-04-23T15:20:09.053892+08:00","gmt_modified":"2026-04-23T15:20:09.053892+08:00"},{"id":242,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e4a49039dae40b7433896c81737fcf8c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-14","gmt_create":"2026-04-23T15:20:09.05437+08:00","gmt_modified":"2026-04-23T15:20:09.05437+08:00"},{"id":243,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"e4a49039dae40b7433896c81737fcf8c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-14","gmt_create":"2026-04-23T15:20:09.054841+08:00","gmt_modified":"2026-04-23T15:20:09.054841+08:00"},{"id":244,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2ee31d68c409e96e951f6cfa7027bca7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-42","gmt_create":"2026-04-23T15:20:09.055328+08:00","gmt_modified":"2026-04-23T15:20:09.055328+08:00"},{"id":245,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"2ee31d68c409e96e951f6cfa7027bca7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-42","gmt_create":"2026-04-23T15:20:09.055781+08:00","gmt_modified":"2026-04-23T15:20:09.055781+08:00"},{"id":246,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"79d6e169e36e6b7493898b5f863e07dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#152-157","gmt_create":"2026-04-23T15:20:09.056898+08:00","gmt_modified":"2026-04-23T15:20:09.056898+08:00"},{"id":247,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"79d6e169e36e6b7493898b5f863e07dc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 152-157","gmt_create":"2026-04-23T15:20:09.057188+08:00","gmt_modified":"2026-04-23T15:20:09.057188+08:00"},{"id":248,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"1552315d5fb9f6d7aba5f7e8fa93a975","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-10","gmt_create":"2026-04-23T15:20:09.058217+08:00","gmt_modified":"2026-04-23T15:20:09.058217+08:00"},{"id":249,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"1552315d5fb9f6d7aba5f7e8fa93a975","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-10","gmt_create":"2026-04-23T15:20:09.058503+08:00","gmt_modified":"2026-04-23T15:20:09.058503+08:00"},{"id":250,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"599cca7536cae4a7e0ae93043c476a7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#10-154","gmt_create":"2026-04-23T15:20:09.058947+08:00","gmt_modified":"2026-04-23T15:20:09.058947+08:00"},{"id":251,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"599cca7536cae4a7e0ae93043c476a7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-154","gmt_create":"2026-04-23T15:20:09.059242+08:00","gmt_modified":"2026-04-23T15:20:09.059242+08:00"},{"id":252,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2ec3d45edd6221e0cedf7f8887fe090d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_scheduler.py#17-123","gmt_create":"2026-04-23T15:20:09.059776+08:00","gmt_modified":"2026-04-23T15:20:09.059776+08:00"},{"id":253,"source_id":"b2f0d46a31a5441594f2e777365fc156","target_id":"2ec3d45edd6221e0cedf7f8887fe090d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-123","gmt_create":"2026-04-23T15:20:09.060064+08:00","gmt_modified":"2026-04-23T15:20:09.060064+08:00"},{"id":254,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"99fe1b288fd41daa86c2dfbab819abf0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/__init__.py","gmt_create":"2026-04-23T15:21:46.707277+08:00","gmt_modified":"2026-04-23T15:21:46.707277+08:00"},{"id":255,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-23T15:21:46.707879+08:00","gmt_modified":"2026-04-23T15:21:46.707879+08:00"},{"id":256,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T15:21:46.708322+08:00","gmt_modified":"2026-04-23T15:21:46.708322+08:00"},{"id":257,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T15:21:46.708702+08:00","gmt_modified":"2026-04-23T15:21:46.708702+08:00"},{"id":258,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T15:21:46.709093+08:00","gmt_modified":"2026-04-23T15:21:46.709093+08:00"},{"id":259,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-04-23T15:21:46.709712+08:00","gmt_modified":"2026-04-23T15:21:46.709713+08:00"},{"id":260,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T15:21:46.710101+08:00","gmt_modified":"2026-04-23T15:21:46.710101+08:00"},{"id":261,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-23T15:21:46.710429+08:00","gmt_modified":"2026-04-23T15:21:46.710429+08:00"},{"id":262,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-04-23T15:21:46.710829+08:00","gmt_modified":"2026-04-23T15:21:46.710829+08:00"},{"id":263,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-23T15:21:46.711181+08:00","gmt_modified":"2026-04-23T15:21:46.711181+08:00"},{"id":264,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T15:21:46.711568+08:00","gmt_modified":"2026-04-23T15:21:46.711568+08:00"},{"id":265,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T15:21:46.711965+08:00","gmt_modified":"2026-04-23T15:21:46.711965+08:00"},{"id":266,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T15:21:46.712296+08:00","gmt_modified":"2026-04-23T15:21:46.712296+08:00"},{"id":267,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T15:21:46.712792+08:00","gmt_modified":"2026-04-23T15:21:46.712792+08:00"},{"id":268,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T15:21:46.713121+08:00","gmt_modified":"2026-04-23T15:21:46.713121+08:00"},{"id":269,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-23T15:21:46.713538+08:00","gmt_modified":"2026-04-23T15:21:46.713538+08:00"},{"id":270,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-23T15:21:46.71408+08:00","gmt_modified":"2026-04-23T15:21:46.71408+08:00"},{"id":271,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T15:21:46.714746+08:00","gmt_modified":"2026-04-23T15:21:46.714746+08:00"},{"id":272,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T15:21:46.715399+08:00","gmt_modified":"2026-04-23T15:21:46.7154+08:00"},{"id":273,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T15:21:46.716178+08:00","gmt_modified":"2026-04-23T15:21:46.716178+08:00"},{"id":274,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-04-23T15:21:46.717324+08:00","gmt_modified":"2026-04-23T15:21:46.717324+08:00"},{"id":275,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-37","gmt_create":"2026-04-23T15:21:46.718049+08:00","gmt_modified":"2026-04-23T15:21:46.71805+08:00"},{"id":276,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T15:21:46.718816+08:00","gmt_modified":"2026-04-23T15:21:46.718816+08:00"},{"id":277,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-123","gmt_create":"2026-04-23T15:21:46.719468+08:00","gmt_modified":"2026-04-23T15:21:46.719468+08:00"},{"id":278,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:21:46.720008+08:00","gmt_modified":"2026-04-23T15:21:46.720008+08:00"},{"id":279,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"121203f7f9f539ffb1456c3f5cdfd842","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-359","gmt_create":"2026-04-23T15:21:46.720615+08:00","gmt_modified":"2026-04-23T15:21:46.720615+08:00"},{"id":280,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"121203f7f9f539ffb1456c3f5cdfd842","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-359","gmt_create":"2026-04-23T15:21:46.721095+08:00","gmt_modified":"2026-04-23T15:21:46.721095+08:00"},{"id":281,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-23T15:21:46.721634+08:00","gmt_modified":"2026-04-23T15:21:46.721634+08:00"},{"id":282,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-86","gmt_create":"2026-04-23T15:21:46.722019+08:00","gmt_modified":"2026-04-23T15:21:46.722019+08:00"},{"id":283,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T15:21:46.722621+08:00","gmt_modified":"2026-04-23T15:21:46.722621+08:00"},{"id":284,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-78","gmt_create":"2026-04-23T15:21:46.723064+08:00","gmt_modified":"2026-04-23T15:21:46.723064+08:00"},{"id":285,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/__init__.py#1-14","gmt_create":"2026-04-23T15:21:46.72357+08:00","gmt_modified":"2026-04-23T15:21:46.72357+08:00"},{"id":286,"source_id":"99fe1b288fd41daa86c2dfbab819abf0","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-04-23T15:21:46.723873+08:00","gmt_modified":"2026-04-23T15:21:46.723873+08:00"},{"id":287,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#21-128","gmt_create":"2026-04-23T15:21:46.726415+08:00","gmt_modified":"2026-04-23T15:21:46.726416+08:00"},{"id":288,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-128","gmt_create":"2026-04-23T15:21:46.726829+08:00","gmt_modified":"2026-04-23T15:21:46.726829+08:00"},{"id":289,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"e454b4a54500bd81e7599e6ec97bf12b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#23-37","gmt_create":"2026-04-23T15:21:46.735019+08:00","gmt_modified":"2026-04-23T15:21:46.735019+08:00"},{"id":290,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"e454b4a54500bd81e7599e6ec97bf12b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-37","gmt_create":"2026-04-23T15:21:46.735734+08:00","gmt_modified":"2026-04-23T15:21:46.735734+08:00"},{"id":291,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1965adf7cfc65447e3c1ae21fbf6d1c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#39-59","gmt_create":"2026-04-23T15:21:46.737007+08:00","gmt_modified":"2026-04-23T15:21:46.737007+08:00"},{"id":292,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"1965adf7cfc65447e3c1ae21fbf6d1c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-59","gmt_create":"2026-04-23T15:21:46.744358+08:00","gmt_modified":"2026-04-23T15:21:46.744358+08:00"},{"id":293,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"c730faefb34bb87c40c5f636b4ff7f41","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#80-94","gmt_create":"2026-04-23T15:21:46.747533+08:00","gmt_modified":"2026-04-23T15:21:46.747534+08:00"},{"id":294,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"c730faefb34bb87c40c5f636b4ff7f41","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 80-94","gmt_create":"2026-04-23T15:21:46.748811+08:00","gmt_modified":"2026-04-23T15:21:46.748811+08:00"},{"id":295,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b9978c3eccea3ef566b003216e5047af","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#61-78","gmt_create":"2026-04-23T15:21:46.751629+08:00","gmt_modified":"2026-04-23T15:21:46.751629+08:00"},{"id":296,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"b9978c3eccea3ef566b003216e5047af","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-78","gmt_create":"2026-04-23T15:21:46.752497+08:00","gmt_modified":"2026-04-23T15:21:46.752497+08:00"},{"id":297,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"eb6ff4361d7413b57f1f70b1ec2f0c94","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#96-111","gmt_create":"2026-04-23T15:21:46.753732+08:00","gmt_modified":"2026-04-23T15:21:46.753732+08:00"},{"id":298,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"eb6ff4361d7413b57f1f70b1ec2f0c94","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 96-111","gmt_create":"2026-04-23T15:21:46.754523+08:00","gmt_modified":"2026-04-23T15:21:46.754523+08:00"},{"id":299,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1a2657244414b5681afded9565a86422","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#35-40","gmt_create":"2026-04-23T15:21:46.755683+08:00","gmt_modified":"2026-04-23T15:21:46.755683+08:00"},{"id":300,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#43-48","gmt_create":"2026-04-23T15:21:46.756979+08:00","gmt_modified":"2026-04-23T15:21:46.756979+08:00"},{"id":301,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#36-38","gmt_create":"2026-04-23T15:21:46.75809+08:00","gmt_modified":"2026-04-23T15:21:46.75809+08:00"},{"id":302,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-38","gmt_create":"2026-04-23T15:21:46.759234+08:00","gmt_modified":"2026-04-23T15:21:46.759234+08:00"},{"id":303,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#37-41","gmt_create":"2026-04-23T15:21:46.760054+08:00","gmt_modified":"2026-04-23T15:21:46.760054+08:00"},{"id":304,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-41","gmt_create":"2026-04-23T15:21:46.761257+08:00","gmt_modified":"2026-04-23T15:21:46.761257+08:00"},{"id":305,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-04-23T15:21:46.76204+08:00","gmt_modified":"2026-04-23T15:21:46.762041+08:00"},{"id":306,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-50","gmt_create":"2026-04-23T15:21:46.763512+08:00","gmt_modified":"2026-04-23T15:21:46.763512+08:00"},{"id":307,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"0907fc2974ec31c23aaaef02076700a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#25-33","gmt_create":"2026-04-23T15:21:46.764956+08:00","gmt_modified":"2026-04-23T15:21:46.764956+08:00"},{"id":308,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"0907fc2974ec31c23aaaef02076700a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-33","gmt_create":"2026-04-23T15:21:46.766604+08:00","gmt_modified":"2026-04-23T15:21:46.766605+08:00"},{"id":309,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"842f74e2cc054608242e93fbefd96b45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#32-40","gmt_create":"2026-04-23T15:21:46.767787+08:00","gmt_modified":"2026-04-23T15:21:46.767787+08:00"},{"id":310,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"842f74e2cc054608242e93fbefd96b45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-40","gmt_create":"2026-04-23T15:21:46.769407+08:00","gmt_modified":"2026-04-23T15:21:46.769407+08:00"},{"id":311,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"aed9e839038c45e6ce2023c4e05adb76","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#27-32","gmt_create":"2026-04-23T15:21:46.770612+08:00","gmt_modified":"2026-04-23T15:21:46.770612+08:00"},{"id":312,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"aed9e839038c45e6ce2023c4e05adb76","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-32","gmt_create":"2026-04-23T15:21:46.771344+08:00","gmt_modified":"2026-04-23T15:21:46.771345+08:00"},{"id":313,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"2181318c993526c86458f5eef134aed6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#62-77","gmt_create":"2026-04-23T15:21:46.77237+08:00","gmt_modified":"2026-04-23T15:21:46.77237+08:00"},{"id":314,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"2181318c993526c86458f5eef134aed6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 62-77","gmt_create":"2026-04-23T15:21:46.773284+08:00","gmt_modified":"2026-04-23T15:21:46.773284+08:00"},{"id":315,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"a817488dc968d761a8977fb5bb8d01a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-129","gmt_create":"2026-04-23T15:21:46.774203+08:00","gmt_modified":"2026-04-23T15:21:46.774203+08:00"},{"id":316,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"a817488dc968d761a8977fb5bb8d01a2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-129","gmt_create":"2026-04-23T15:21:46.775081+08:00","gmt_modified":"2026-04-23T15:21:46.775081+08:00"},{"id":317,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T15:21:46.775898+08:00","gmt_modified":"2026-04-23T15:21:46.775898+08:00"},{"id":318,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7","gmt_create":"2026-04-23T15:21:46.777494+08:00","gmt_modified":"2026-04-23T15:21:46.777494+08:00"},{"id":319,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7","gmt_create":"2026-04-23T15:21:46.778103+08:00","gmt_modified":"2026-04-23T15:21:46.778103+08:00"},{"id":320,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-23T15:21:46.779313+08:00","gmt_modified":"2026-04-23T15:21:46.779314+08:00"},{"id":321,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T15:21:46.780075+08:00","gmt_modified":"2026-04-23T15:21:46.780075+08:00"},{"id":322,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"37868a5af96edcdad149caf9a184435a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#42-85","gmt_create":"2026-04-23T15:21:46.781141+08:00","gmt_modified":"2026-04-23T15:21:46.781141+08:00"},{"id":323,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"37868a5af96edcdad149caf9a184435a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-85","gmt_create":"2026-04-23T15:21:46.781803+08:00","gmt_modified":"2026-04-23T15:21:46.781803+08:00"},{"id":324,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#18-33","gmt_create":"2026-04-23T15:21:46.783498+08:00","gmt_modified":"2026-04-23T15:21:46.783498+08:00"},{"id":325,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-33","gmt_create":"2026-04-23T15:21:46.784342+08:00","gmt_modified":"2026-04-23T15:21:46.784343+08:00"},{"id":344,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:22:16.017503+08:00","gmt_modified":"2026-04-23T15:22:16.017503+08:00"},{"id":346,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-48","gmt_create":"2026-04-23T15:22:16.019099+08:00","gmt_modified":"2026-04-23T15:22:16.019099+08:00"},{"id":348,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-04-23T15:22:16.020577+08:00","gmt_modified":"2026-04-23T15:22:16.020577+08:00"},{"id":350,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-04-23T15:22:16.021841+08:00","gmt_modified":"2026-04-23T15:22:16.021841+08:00"},{"id":354,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-309","gmt_create":"2026-04-23T15:22:16.023827+08:00","gmt_modified":"2026-04-23T15:22:16.023827+08:00"},{"id":356,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"9630036e63fc15cb81b202cf79671aab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-182","gmt_create":"2026-04-23T15:22:16.024606+08:00","gmt_modified":"2026-04-23T15:22:16.024606+08:00"},{"id":359,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-17","gmt_create":"2026-04-23T15:22:16.026089+08:00","gmt_modified":"2026-04-23T15:22:16.02609+08:00"},{"id":361,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-123","gmt_create":"2026-04-23T15:22:16.02774+08:00","gmt_modified":"2026-04-23T15:22:16.02774+08:00"},{"id":363,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"9df233ef1be4b95068ed91bf01083ae7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 117-123","gmt_create":"2026-04-23T15:22:16.028504+08:00","gmt_modified":"2026-04-23T15:22:16.028504+08:00"},{"id":365,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-42","gmt_create":"2026-04-23T15:22:16.029449+08:00","gmt_modified":"2026-04-23T15:22:16.029449+08:00"},{"id":367,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-43","gmt_create":"2026-04-23T15:22:16.030648+08:00","gmt_modified":"2026-04-23T15:22:16.030648+08:00"},{"id":369,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-43","gmt_create":"2026-04-23T15:22:16.03168+08:00","gmt_modified":"2026-04-23T15:22:16.03168+08:00"},{"id":372,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"735aef72b4fe6ca4f407e69b7dda8b43","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-78","gmt_create":"2026-04-23T15:22:16.03298+08:00","gmt_modified":"2026-04-23T15:22:16.03298+08:00"},{"id":374,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"8128dd67cf376d2cadf7c2d3831c380a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-29","gmt_create":"2026-04-23T15:22:16.035564+08:00","gmt_modified":"2026-04-23T15:22:16.035564+08:00"},{"id":376,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-104","gmt_create":"2026-04-23T15:22:16.036753+08:00","gmt_modified":"2026-04-23T15:22:16.036753+08:00"},{"id":378,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"753a437d837246ead62b0e16c6331284","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-69","gmt_create":"2026-04-23T15:22:16.038261+08:00","gmt_modified":"2026-04-23T15:22:16.038261+08:00"},{"id":380,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-104","gmt_create":"2026-04-23T15:22:16.039369+08:00","gmt_modified":"2026-04-23T15:22:16.039369+08:00"},{"id":382,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-69","gmt_create":"2026-04-23T15:22:16.040483+08:00","gmt_modified":"2026-04-23T15:22:16.040483+08:00"},{"id":385,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 122-146","gmt_create":"2026-04-23T15:22:16.042829+08:00","gmt_modified":"2026-04-23T15:22:16.042829+08:00"},{"id":388,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"a57acd9da5287c915ac823784a409292","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-127","gmt_create":"2026-04-23T15:22:16.045132+08:00","gmt_modified":"2026-04-23T15:22:16.045132+08:00"},{"id":390,"source_id":"42ff5383133d176cec9eb88682483be3","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-93","gmt_create":"2026-04-23T15:22:16.046367+08:00","gmt_modified":"2026-04-23T15:22:16.046367+08:00"},{"id":392,"source_id":"42ff5383133d176cec9eb88682483be3","target_id":"692ac240965eff7e66945aa3c4c270f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-93","gmt_create":"2026-04-23T15:22:16.047995+08:00","gmt_modified":"2026-04-23T15:22:16.047995+08:00"},{"id":394,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"32a0a52faca2d8d488e49c63c86075b1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-154","gmt_create":"2026-04-23T15:22:16.049251+08:00","gmt_modified":"2026-04-23T15:22:16.049251+08:00"},{"id":396,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-154","gmt_create":"2026-04-23T15:22:16.051952+08:00","gmt_modified":"2026-04-23T15:22:16.051952+08:00"},{"id":398,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"3a6e1b738967bf8cc651e57f48e2e126","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 83-126","gmt_create":"2026-04-23T15:22:16.053692+08:00","gmt_modified":"2026-04-23T15:22:16.053693+08:00"},{"id":400,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"b1afd377757f1d0e9bdf87edfff3ad88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 131-186","gmt_create":"2026-04-23T15:22:16.054533+08:00","gmt_modified":"2026-04-23T15:22:16.054533+08:00"},{"id":402,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"de05ec7eed033e432991e5a88e1b5a06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 192-222","gmt_create":"2026-04-23T15:22:16.055495+08:00","gmt_modified":"2026-04-23T15:22:16.055495+08:00"},{"id":404,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"7fd61a451248b6b129299d6246f711c7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 228-296","gmt_create":"2026-04-23T15:22:16.056294+08:00","gmt_modified":"2026-04-23T15:22:16.056294+08:00"},{"id":406,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"53eedffff456a566fa7b0cecc7169f56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-441","gmt_create":"2026-04-23T15:22:16.05703+08:00","gmt_modified":"2026-04-23T15:22:16.05703+08:00"},{"id":408,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"906f7a8288e38d4244211f3f538fe7b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-182","gmt_create":"2026-04-23T15:22:16.062545+08:00","gmt_modified":"2026-04-23T15:22:16.062545+08:00"},{"id":410,"source_id":"b2f0d46a31a5441594f2e777365fc156","target_id":"1647ee2066de2ae59ba8cf88e33c5e02","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:22:16.064587+08:00","gmt_modified":"2026-04-23T15:22:16.064587+08:00"},{"id":411,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-23T15:22:23.52554+08:00","gmt_modified":"2026-04-23T15:22:23.52554+08:00"},{"id":412,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-04-23T15:22:23.52643+08:00","gmt_modified":"2026-04-23T15:22:23.526431+08:00"},{"id":413,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"f93ae024fe0a2e69698037dff6df205f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/utils.ts","gmt_create":"2026-04-23T15:22:23.527272+08:00","gmt_modified":"2026-04-23T15:22:23.527272+08:00"},{"id":414,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ac1acbc54c49ee1de13369f6c6827568","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/button.tsx","gmt_create":"2026-04-23T15:22:23.528155+08:00","gmt_modified":"2026-04-23T15:22:23.528155+08:00"},{"id":415,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"108b0c4b4dcfb6aa39a5eb138225c148","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dialog.tsx","gmt_create":"2026-04-23T15:22:23.529196+08:00","gmt_modified":"2026-04-23T15:22:23.529196+08:00"},{"id":416,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0186dc8a89340139a84e1e3c5571a57f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dropdown-menu.tsx","gmt_create":"2026-04-23T15:22:23.530077+08:00","gmt_modified":"2026-04-23T15:22:23.530077+08:00"},{"id":417,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3cf787fa77a15b2b1783560c6d83ed21","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/input.tsx","gmt_create":"2026-04-23T15:22:23.530977+08:00","gmt_modified":"2026-04-23T15:22:23.530977+08:00"},{"id":418,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3c56e1c079959bfcc985183805e5874f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/select.tsx","gmt_create":"2026-04-23T15:22:23.531664+08:00","gmt_modified":"2026-04-23T15:22:23.531664+08:00"},{"id":419,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/card.tsx","gmt_create":"2026-04-23T15:22:23.532588+08:00","gmt_modified":"2026-04-23T15:22:23.532588+08:00"},{"id":420,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"51821ca9ec2a1c972f3c9d111e19db8a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/badge.tsx","gmt_create":"2026-04-23T15:22:23.53409+08:00","gmt_modified":"2026-04-23T15:22:23.53409+08:00"},{"id":421,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/table.tsx","gmt_create":"2026-04-23T15:22:23.535512+08:00","gmt_modified":"2026-04-23T15:22:23.535512+08:00"},{"id":422,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"beb87ab5aad9532647e9dbd2db7ef587","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/tabs.tsx","gmt_create":"2026-04-23T15:22:23.536664+08:00","gmt_modified":"2026-04-23T15:22:23.536665+08:00"},{"id":423,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"792b8e2c16c9ff2095d83b8972313be4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/label.tsx","gmt_create":"2026-04-23T15:22:23.537365+08:00","gmt_modified":"2026-04-23T15:22:23.537365+08:00"},{"id":424,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"546e01c5f73aaf5140eee922f4b9a441","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/providers.tsx","gmt_create":"2026-04-23T15:22:23.538246+08:00","gmt_modified":"2026-04-23T15:22:23.538246+08:00"},{"id":425,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-23T15:22:23.53929+08:00","gmt_modified":"2026-04-23T15:22:23.53929+08:00"},{"id":426,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-04-23T15:22:23.540469+08:00","gmt_modified":"2026-04-23T15:22:23.540469+08:00"},{"id":427,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-23T15:22:23.541484+08:00","gmt_modified":"2026-04-23T15:22:23.541484+08:00"},{"id":428,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"fd18328b6582e68c30b130b912891992","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/providers.tsx#1-9","gmt_create":"2026-04-23T15:22:23.542098+08:00","gmt_modified":"2026-04-23T15:22:23.542098+08:00"},{"id":429,"source_id":"546e01c5f73aaf5140eee922f4b9a441","target_id":"fd18328b6582e68c30b130b912891992","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-9","gmt_create":"2026-04-23T15:22:23.542482+08:00","gmt_modified":"2026-04-23T15:22:23.542482+08:00"},{"id":430,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#1-7","gmt_create":"2026-04-23T15:22:23.542958+08:00","gmt_modified":"2026-04-23T15:22:23.542958+08:00"},{"id":431,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-23T15:22:23.54348+08:00","gmt_modified":"2026-04-23T15:22:23.54348+08:00"},{"id":432,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-40","gmt_create":"2026-04-23T15:22:23.543767+08:00","gmt_modified":"2026-04-23T15:22:23.543768+08:00"},{"id":433,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-57","gmt_create":"2026-04-23T15:22:23.544176+08:00","gmt_modified":"2026-04-23T15:22:23.544176+08:00"},{"id":434,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:22:23.544513+08:00","gmt_modified":"2026-04-23T15:22:23.544513+08:00"},{"id":435,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#1-57","gmt_create":"2026-04-23T15:22:23.545023+08:00","gmt_modified":"2026-04-23T15:22:23.545023+08:00"},{"id":436,"source_id":"ac1acbc54c49ee1de13369f6c6827568","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:22:23.545376+08:00","gmt_modified":"2026-04-23T15:22:23.545376+08:00"},{"id":437,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"607bb628918a7a5d54cbf74763f94d07","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/input.tsx#1-23","gmt_create":"2026-04-23T15:22:23.545898+08:00","gmt_modified":"2026-04-23T15:22:23.545899+08:00"},{"id":438,"source_id":"3cf787fa77a15b2b1783560c6d83ed21","target_id":"607bb628918a7a5d54cbf74763f94d07","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T15:22:23.546272+08:00","gmt_modified":"2026-04-23T15:22:23.546272+08:00"},{"id":439,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/select.tsx#1-161","gmt_create":"2026-04-23T15:22:23.546653+08:00","gmt_modified":"2026-04-23T15:22:23.546653+08:00"},{"id":440,"source_id":"3c56e1c079959bfcc985183805e5874f","target_id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-161","gmt_create":"2026-04-23T15:22:23.546906+08:00","gmt_modified":"2026-04-23T15:22:23.546907+08:00"},{"id":441,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#1-123","gmt_create":"2026-04-23T15:22:23.547243+08:00","gmt_modified":"2026-04-23T15:22:23.547244+08:00"},{"id":442,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ad6ff021b2126ad5c42323305eb6d8b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dropdown-menu.tsx#1-201","gmt_create":"2026-04-23T15:22:23.547645+08:00","gmt_modified":"2026-04-23T15:22:23.547645+08:00"},{"id":443,"source_id":"0186dc8a89340139a84e1e3c5571a57f","target_id":"ad6ff021b2126ad5c42323305eb6d8b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-201","gmt_create":"2026-04-23T15:22:23.547892+08:00","gmt_modified":"2026-04-23T15:22:23.547892+08:00"},{"id":444,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"a85f004dca63614b4e734ba63b45ef9e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/card.tsx#1-80","gmt_create":"2026-04-23T15:22:23.548296+08:00","gmt_modified":"2026-04-23T15:22:23.548296+08:00"},{"id":445,"source_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","target_id":"a85f004dca63614b4e734ba63b45ef9e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-80","gmt_create":"2026-04-23T15:22:23.548561+08:00","gmt_modified":"2026-04-23T15:22:23.548561+08:00"},{"id":446,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#1-118","gmt_create":"2026-04-23T15:22:23.548946+08:00","gmt_modified":"2026-04-23T15:22:23.548946+08:00"},{"id":447,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#1-56","gmt_create":"2026-04-23T15:22:23.549383+08:00","gmt_modified":"2026-04-23T15:22:23.549383+08:00"},{"id":448,"source_id":"beb87ab5aad9532647e9dbd2db7ef587","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-56","gmt_create":"2026-04-23T15:22:23.549652+08:00","gmt_modified":"2026-04-23T15:22:23.549653+08:00"},{"id":449,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"379443f450513b5492e2d9d5fca94a42","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/label.tsx#1-27","gmt_create":"2026-04-23T15:22:23.550013+08:00","gmt_modified":"2026-04-23T15:22:23.550014+08:00"},{"id":450,"source_id":"792b8e2c16c9ff2095d83b8972313be4","target_id":"379443f450513b5492e2d9d5fca94a42","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-27","gmt_create":"2026-04-23T15:22:23.550267+08:00","gmt_modified":"2026-04-23T15:22:23.550267+08:00"},{"id":451,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4aa6ad434a73143bb7a2072124f63be0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/badge.tsx#1-37","gmt_create":"2026-04-23T15:22:23.551155+08:00","gmt_modified":"2026-04-23T15:22:23.551155+08:00"},{"id":452,"source_id":"51821ca9ec2a1c972f3c9d111e19db8a","target_id":"4aa6ad434a73143bb7a2072124f63be0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T15:22:23.551858+08:00","gmt_modified":"2026-04-23T15:22:23.551858+08:00"},{"id":453,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"c45dbdda70a8b9f02b52af4991644d0b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#11-27","gmt_create":"2026-04-23T15:22:23.552353+08:00","gmt_modified":"2026-04-23T15:22:23.552353+08:00"},{"id":454,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"c45dbdda70a8b9f02b52af4991644d0b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-27","gmt_create":"2026-04-23T15:22:23.552845+08:00","gmt_modified":"2026-04-23T15:22:23.552845+08:00"},{"id":455,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"6ac6943c93570294e4fb15a862be2616","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#36-54","gmt_create":"2026-04-23T15:22:23.553797+08:00","gmt_modified":"2026-04-23T15:22:23.553797+08:00"},{"id":456,"source_id":"ac1acbc54c49ee1de13369f6c6827568","target_id":"6ac6943c93570294e4fb15a862be2616","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-54","gmt_create":"2026-04-23T15:22:23.554077+08:00","gmt_modified":"2026-04-23T15:22:23.554077+08:00"},{"id":457,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4bfb5059c685e9878aed64cb5347ccec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#9-54","gmt_create":"2026-04-23T15:22:23.554645+08:00","gmt_modified":"2026-04-23T15:22:23.554645+08:00"},{"id":458,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"4bfb5059c685e9878aed64cb5347ccec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-54","gmt_create":"2026-04-23T15:22:23.554875+08:00","gmt_modified":"2026-04-23T15:22:23.554875+08:00"},{"id":459,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0af48b69fe8fb9e480fa1656f36a4330","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dropdown-menu.tsx#21-75","gmt_create":"2026-04-23T15:22:23.555418+08:00","gmt_modified":"2026-04-23T15:22:23.555418+08:00"},{"id":460,"source_id":"0186dc8a89340139a84e1e3c5571a57f","target_id":"0af48b69fe8fb9e480fa1656f36a4330","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-75","gmt_create":"2026-04-23T15:22:23.55574+08:00","gmt_modified":"2026-04-23T15:22:23.55574+08:00"},{"id":461,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"09971e31ab658e119d4c0ad948282107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/select.tsx#15-100","gmt_create":"2026-04-23T15:22:23.556401+08:00","gmt_modified":"2026-04-23T15:22:23.556401+08:00"},{"id":462,"source_id":"3c56e1c079959bfcc985183805e5874f","target_id":"09971e31ab658e119d4c0ad948282107","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-100","gmt_create":"2026-04-23T15:22:23.556634+08:00","gmt_modified":"2026-04-23T15:22:23.556634+08:00"},{"id":463,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"31aa8777de6043883950d2668094e388","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#5-106","gmt_create":"2026-04-23T15:22:23.55717+08:00","gmt_modified":"2026-04-23T15:22:23.55717+08:00"},{"id":464,"source_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","target_id":"31aa8777de6043883950d2668094e388","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-106","gmt_create":"2026-04-23T15:22:23.557428+08:00","gmt_modified":"2026-04-23T15:22:23.557429+08:00"},{"id":465,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"28baf3cedb89a21c6d542b7ce2439b24","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#8-53","gmt_create":"2026-04-23T15:22:23.558002+08:00","gmt_modified":"2026-04-23T15:22:23.558002+08:00"},{"id":466,"source_id":"beb87ab5aad9532647e9dbd2db7ef587","target_id":"28baf3cedb89a21c6d542b7ce2439b24","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-53","gmt_create":"2026-04-23T15:22:23.558316+08:00","gmt_modified":"2026-04-23T15:22:23.558316+08:00"},{"id":467,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"28b0f4797c6084272244175a24b961cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/card.tsx#5-77","gmt_create":"2026-04-23T15:22:23.558858+08:00","gmt_modified":"2026-04-23T15:22:23.558858+08:00"},{"id":468,"source_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","target_id":"28b0f4797c6084272244175a24b961cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-77","gmt_create":"2026-04-23T15:22:23.559082+08:00","gmt_modified":"2026-04-23T15:22:23.559082+08:00"},{"id":469,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"a6e0b3fa65906c3c3cd88707e1d40059","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/label.tsx#9-23","gmt_create":"2026-04-23T15:22:23.559653+08:00","gmt_modified":"2026-04-23T15:22:23.559653+08:00"},{"id":470,"source_id":"792b8e2c16c9ff2095d83b8972313be4","target_id":"a6e0b3fa65906c3c3cd88707e1d40059","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-23","gmt_create":"2026-04-23T15:22:23.560391+08:00","gmt_modified":"2026-04-23T15:22:23.560392+08:00"},{"id":471,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"9a909775022010b4686c2b00cdf1c165","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/badge.tsx#6-34","gmt_create":"2026-04-23T15:22:23.562216+08:00","gmt_modified":"2026-04-23T15:22:23.562216+08:00"},{"id":472,"source_id":"51821ca9ec2a1c972f3c9d111e19db8a","target_id":"9a909775022010b4686c2b00cdf1c165","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-34","gmt_create":"2026-04-23T15:22:23.562602+08:00","gmt_modified":"2026-04-23T15:22:23.562602+08:00"},{"id":473,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ce1cd184945ae56cf63f55168afd8050","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#47-50","gmt_create":"2026-04-23T15:22:23.565009+08:00","gmt_modified":"2026-04-23T15:22:23.565009+08:00"},{"id":474,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"ce1cd184945ae56cf63f55168afd8050","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-50","gmt_create":"2026-04-23T15:22:23.565469+08:00","gmt_modified":"2026-04-23T15:22:23.565469+08:00"},{"id":475,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4a2a06e1efcbc85deaa013dca155f20c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#10-54","gmt_create":"2026-04-23T15:22:23.57102+08:00","gmt_modified":"2026-04-23T15:22:23.57102+08:00"},{"id":476,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"4a2a06e1efcbc85deaa013dca155f20c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-54","gmt_create":"2026-04-23T15:22:23.571491+08:00","gmt_modified":"2026-04-23T15:22:23.571491+08:00"},{"id":477,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"8b00ea4aba57ea6ed982287fb7840805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#4-6","gmt_create":"2026-04-23T15:22:23.572188+08:00","gmt_modified":"2026-04-23T15:22:23.572188+08:00"},{"id":478,"source_id":"f93ae024fe0a2e69698037dff6df205f","target_id":"8b00ea4aba57ea6ed982287fb7840805","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-6","gmt_create":"2026-04-23T15:22:23.572722+08:00","gmt_modified":"2026-04-23T15:22:23.572722+08:00"},{"id":483,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2fc79486-ec65-4533-860a-89c8877c2ea0","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e 2fc79486-ec65-4533-860a-89c8877c2ea0","gmt_create":"2026-04-23T15:22:24.563092+08:00","gmt_modified":"2026-04-23T15:22:24.563092+08:00"},{"id":484,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","gmt_create":"2026-04-23T15:22:24.564188+08:00","gmt_modified":"2026-04-23T15:22:24.564188+08:00"},{"id":492,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:31:36.520458+08:00","gmt_modified":"2026-04-23T20:31:36.520458+08:00"},{"id":493,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:31:36.521676+08:00","gmt_modified":"2026-04-23T20:31:36.521677+08:00"},{"id":494,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:31:36.522472+08:00","gmt_modified":"2026-04-23T20:31:36.522472+08:00"},{"id":495,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:31:36.522898+08:00","gmt_modified":"2026-04-23T20:31:36.522898+08:00"},{"id":496,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"404f6d0765a8c6e77e33b7fc21b377a4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/doubao.py","gmt_create":"2026-04-23T20:31:36.523305+08:00","gmt_modified":"2026-04-23T20:31:36.523305+08:00"},{"id":497,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"303e80519e946904d1cb3ac32cbb0814","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/qingyan.py","gmt_create":"2026-04-23T20:31:36.524292+08:00","gmt_modified":"2026-04-23T20:31:36.524292+08:00"},{"id":498,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"5af7301fe056fc3d10820d820e8ad777","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tiangong.py","gmt_create":"2026-04-23T20:31:36.525283+08:00","gmt_modified":"2026-04-23T20:31:36.525283+08:00"},{"id":499,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"0e38ad5d2d3daaad08c9302df8805b15","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/xinghuo.py","gmt_create":"2026-04-23T20:31:36.52736+08:00","gmt_modified":"2026-04-23T20:31:36.52736+08:00"},{"id":500,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:31:36.527985+08:00","gmt_modified":"2026-04-23T20:31:36.527985+08:00"},{"id":501,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:31:36.530076+08:00","gmt_modified":"2026-04-23T20:31:36.530076+08:00"},{"id":502,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:31:36.531496+08:00","gmt_modified":"2026-04-23T20:31:36.531496+08:00"},{"id":503,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:31:36.532308+08:00","gmt_modified":"2026-04-23T20:31:36.532308+08:00"},{"id":504,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:31:36.533202+08:00","gmt_modified":"2026-04-23T20:31:36.533203+08:00"},{"id":505,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:31:36.533733+08:00","gmt_modified":"2026-04-23T20:31:36.533733+08:00"},{"id":506,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:31:36.534166+08:00","gmt_modified":"2026-04-23T20:31:36.534166+08:00"},{"id":507,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:31:36.535208+08:00","gmt_modified":"2026-04-23T20:31:36.535208+08:00"},{"id":508,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:31:36.536177+08:00","gmt_modified":"2026-04-23T20:31:36.536177+08:00"},{"id":509,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T20:31:36.536784+08:00","gmt_modified":"2026-04-23T20:31:36.536784+08:00"},{"id":510,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-04-23T20:31:36.537249+08:00","gmt_modified":"2026-04-23T20:31:36.537249+08:00"},{"id":511,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-23T20:31:36.53817+08:00","gmt_modified":"2026-04-23T20:31:36.538171+08:00"},{"id":512,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T20:31:36.53929+08:00","gmt_modified":"2026-04-23T20:31:36.53929+08:00"},{"id":513,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-269","gmt_create":"2026-04-23T20:31:36.540413+08:00","gmt_modified":"2026-04-23T20:31:36.540413+08:00"},{"id":514,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-269","gmt_create":"2026-04-23T20:31:36.541301+08:00","gmt_modified":"2026-04-23T20:31:36.541301+08:00"},{"id":515,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:31:36.541996+08:00","gmt_modified":"2026-04-23T20:31:36.541996+08:00"},{"id":516,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-95","gmt_create":"2026-04-23T20:31:36.542269+08:00","gmt_modified":"2026-04-23T20:31:36.542269+08:00"},{"id":517,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-330","gmt_create":"2026-04-23T20:31:36.543463+08:00","gmt_modified":"2026-04-23T20:31:36.543463+08:00"},{"id":518,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-330","gmt_create":"2026-04-23T20:31:36.543912+08:00","gmt_modified":"2026-04-23T20:31:36.543912+08:00"},{"id":519,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#1-38","gmt_create":"2026-04-23T20:31:36.545278+08:00","gmt_modified":"2026-04-23T20:31:36.545279+08:00"},{"id":520,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.545752+08:00","gmt_modified":"2026-04-23T20:31:36.545752+08:00"},{"id":521,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#1-38","gmt_create":"2026-04-23T20:31:36.546456+08:00","gmt_modified":"2026-04-23T20:31:36.546457+08:00"},{"id":522,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.546804+08:00","gmt_modified":"2026-04-23T20:31:36.546804+08:00"},{"id":523,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#1-38","gmt_create":"2026-04-23T20:31:36.547594+08:00","gmt_modified":"2026-04-23T20:31:36.547594+08:00"},{"id":524,"source_id":"303e80519e946904d1cb3ac32cbb0814","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.548009+08:00","gmt_modified":"2026-04-23T20:31:36.548009+08:00"},{"id":525,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#1-38","gmt_create":"2026-04-23T20:31:36.548333+08:00","gmt_modified":"2026-04-23T20:31:36.548333+08:00"},{"id":526,"source_id":"5af7301fe056fc3d10820d820e8ad777","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.548917+08:00","gmt_modified":"2026-04-23T20:31:36.548917+08:00"},{"id":527,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#1-38","gmt_create":"2026-04-23T20:31:36.549296+08:00","gmt_modified":"2026-04-23T20:31:36.549296+08:00"},{"id":528,"source_id":"0e38ad5d2d3daaad08c9302df8805b15","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.54956+08:00","gmt_modified":"2026-04-23T20:31:36.54956+08:00"},{"id":529,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:31:36.549907+08:00","gmt_modified":"2026-04-23T20:31:36.549907+08:00"},{"id":530,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-174","gmt_create":"2026-04-23T20:31:36.55085+08:00","gmt_modified":"2026-04-23T20:31:36.55085+08:00"},{"id":531,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-23T20:31:36.551428+08:00","gmt_modified":"2026-04-23T20:31:36.551428+08:00"},{"id":532,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:31:36.552386+08:00","gmt_modified":"2026-04-23T20:31:36.552386+08:00"},{"id":533,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-55","gmt_create":"2026-04-23T20:31:36.553134+08:00","gmt_modified":"2026-04-23T20:31:36.553134+08:00"},{"id":534,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:31:36.553656+08:00","gmt_modified":"2026-04-23T20:31:36.553656+08:00"},{"id":535,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-42","gmt_create":"2026-04-23T20:31:36.554174+08:00","gmt_modified":"2026-04-23T20:31:36.554174+08:00"},{"id":536,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:31:36.555503+08:00","gmt_modified":"2026-04-23T20:31:36.555503+08:00"},{"id":537,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-39","gmt_create":"2026-04-23T20:31:36.556658+08:00","gmt_modified":"2026-04-23T20:31:36.556658+08:00"},{"id":538,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:31:36.558991+08:00","gmt_modified":"2026-04-23T20:31:36.558991+08:00"},{"id":539,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-18","gmt_create":"2026-04-23T20:31:36.559781+08:00","gmt_modified":"2026-04-23T20:31:36.559781+08:00"},{"id":540,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"300e43c7a648440163f81039eaa47b5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-24","gmt_create":"2026-04-23T20:31:36.563289+08:00","gmt_modified":"2026-04-23T20:31:36.563289+08:00"},{"id":541,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"300e43c7a648440163f81039eaa47b5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-24","gmt_create":"2026-04-23T20:31:36.563813+08:00","gmt_modified":"2026-04-23T20:31:36.563813+08:00"},{"id":542,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"caf1970ded8fc5d3921005e166e2100b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-78","gmt_create":"2026-04-23T20:31:36.567359+08:00","gmt_modified":"2026-04-23T20:31:36.567359+08:00"},{"id":543,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"caf1970ded8fc5d3921005e166e2100b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-78","gmt_create":"2026-04-23T20:31:36.567845+08:00","gmt_modified":"2026-04-23T20:31:36.567845+08:00"},{"id":544,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-234","gmt_create":"2026-04-23T20:31:36.568622+08:00","gmt_modified":"2026-04-23T20:31:36.568622+08:00"},{"id":545,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 204-234","gmt_create":"2026-04-23T20:31:36.569217+08:00","gmt_modified":"2026-04-23T20:31:36.569217+08:00"},{"id":546,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:31:36.569785+08:00","gmt_modified":"2026-04-23T20:31:36.569785+08:00"},{"id":547,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-84","gmt_create":"2026-04-23T20:31:36.570169+08:00","gmt_modified":"2026-04-23T20:31:36.570169+08:00"},{"id":548,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:31:36.570576+08:00","gmt_modified":"2026-04-23T20:31:36.570576+08:00"},{"id":549,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"362d22f423631cda39404660b3317a2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 177-254","gmt_create":"2026-04-23T20:31:36.571472+08:00","gmt_modified":"2026-04-23T20:31:36.571472+08:00"},{"id":550,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#16-33","gmt_create":"2026-04-23T20:31:36.572484+08:00","gmt_modified":"2026-04-23T20:31:36.572484+08:00"},{"id":551,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:31:36.573312+08:00","gmt_modified":"2026-04-23T20:31:36.573312+08:00"},{"id":552,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:31:36.574111+08:00","gmt_modified":"2026-04-23T20:31:36.574112+08:00"},{"id":553,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 163-174","gmt_create":"2026-04-23T20:31:36.574746+08:00","gmt_modified":"2026-04-23T20:31:36.574746+08:00"},{"id":554,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"75c6ab0599d304bf36d290d4143d3d2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#29-31","gmt_create":"2026-04-23T20:31:36.590144+08:00","gmt_modified":"2026-04-23T20:31:36.590144+08:00"},{"id":555,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"75c6ab0599d304bf36d290d4143d3d2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-31","gmt_create":"2026-04-23T20:31:36.591214+08:00","gmt_modified":"2026-04-23T20:31:36.591214+08:00"},{"id":556,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:31:36.591664+08:00","gmt_modified":"2026-04-23T20:31:36.591664+08:00"},{"id":557,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:31:36.592665+08:00","gmt_modified":"2026-04-23T20:31:36.592666+08:00"},{"id":558,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2a6780838f1415dcb7d0fa611f64cee7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-17","gmt_create":"2026-04-23T20:31:36.593186+08:00","gmt_modified":"2026-04-23T20:31:36.593186+08:00"},{"id":559,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"2a6780838f1415dcb7d0fa611f64cee7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-17","gmt_create":"2026-04-23T20:31:36.59372+08:00","gmt_modified":"2026-04-23T20:31:36.59372+08:00"},{"id":560,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#10-38","gmt_create":"2026-04-23T20:31:36.595227+08:00","gmt_modified":"2026-04-23T20:31:36.595227+08:00"},{"id":561,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.596503+08:00","gmt_modified":"2026-04-23T20:31:36.596503+08:00"},{"id":562,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"aa8c3fa3bc509dafe64d113bdd09eafa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#10-38","gmt_create":"2026-04-23T20:31:36.597069+08:00","gmt_modified":"2026-04-23T20:31:36.597069+08:00"},{"id":563,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"aa8c3fa3bc509dafe64d113bdd09eafa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.597765+08:00","gmt_modified":"2026-04-23T20:31:36.597765+08:00"},{"id":564,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"eabb031e538ea62cab69b01368740d20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#10-38","gmt_create":"2026-04-23T20:31:36.598445+08:00","gmt_modified":"2026-04-23T20:31:36.598445+08:00"},{"id":565,"source_id":"303e80519e946904d1cb3ac32cbb0814","target_id":"eabb031e538ea62cab69b01368740d20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.599093+08:00","gmt_modified":"2026-04-23T20:31:36.599093+08:00"},{"id":566,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b1c09e372a63e9854886adaea1663bea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#10-38","gmt_create":"2026-04-23T20:31:36.599896+08:00","gmt_modified":"2026-04-23T20:31:36.599896+08:00"},{"id":567,"source_id":"5af7301fe056fc3d10820d820e8ad777","target_id":"b1c09e372a63e9854886adaea1663bea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.600604+08:00","gmt_modified":"2026-04-23T20:31:36.600604+08:00"},{"id":568,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"79793bcd507f9d287d19014b60d963d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#10-38","gmt_create":"2026-04-23T20:31:36.601204+08:00","gmt_modified":"2026-04-23T20:31:36.601204+08:00"},{"id":569,"source_id":"0e38ad5d2d3daaad08c9302df8805b15","target_id":"79793bcd507f9d287d19014b60d963d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.60148+08:00","gmt_modified":"2026-04-23T20:31:36.60148+08:00"},{"id":570,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-144","gmt_create":"2026-04-23T20:31:36.603752+08:00","gmt_modified":"2026-04-23T20:31:36.603752+08:00"},{"id":571,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-144","gmt_create":"2026-04-23T20:31:36.606514+08:00","gmt_modified":"2026-04-23T20:31:36.606514+08:00"},{"id":572,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:31:36.609013+08:00","gmt_modified":"2026-04-23T20:31:36.609013+08:00"},{"id":573,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 256-287","gmt_create":"2026-04-23T20:31:36.609501+08:00","gmt_modified":"2026-04-23T20:31:36.609501+08:00"},{"id":574,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8af91caf063c12c8236f9675769ce4a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#1-54","gmt_create":"2026-04-23T20:31:36.610558+08:00","gmt_modified":"2026-04-23T20:31:36.610558+08:00"},{"id":575,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"8af91caf063c12c8236f9675769ce4a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-54","gmt_create":"2026-04-23T20:31:36.610946+08:00","gmt_modified":"2026-04-23T20:31:36.610946+08:00"},{"id":576,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"005172b71dc742cf6803c5eb0185091e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-36","gmt_create":"2026-04-23T20:31:36.612653+08:00","gmt_modified":"2026-04-23T20:31:36.612653+08:00"},{"id":577,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"005172b71dc742cf6803c5eb0185091e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-36","gmt_create":"2026-04-23T20:31:36.613263+08:00","gmt_modified":"2026-04-23T20:31:36.613263+08:00"},{"id":578,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:31:36.614861+08:00","gmt_modified":"2026-04-23T20:31:36.614861+08:00"},{"id":579,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 139-144","gmt_create":"2026-04-23T20:31:36.615692+08:00","gmt_modified":"2026-04-23T20:31:36.615692+08:00"},{"id":580,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"384b1939e53970ce7ae75d241a49da5f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#22-29","gmt_create":"2026-04-23T20:31:36.615996+08:00","gmt_modified":"2026-04-23T20:31:36.615996+08:00"},{"id":581,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"384b1939e53970ce7ae75d241a49da5f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-29","gmt_create":"2026-04-23T20:31:36.61682+08:00","gmt_modified":"2026-04-23T20:31:36.61682+08:00"},{"id":582,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:31:36.617171+08:00","gmt_modified":"2026-04-23T20:31:36.617171+08:00"},{"id":583,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 231-247","gmt_create":"2026-04-23T20:31:36.617385+08:00","gmt_modified":"2026-04-23T20:31:36.617385+08:00"},{"id":584,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"15b8ebf74b0a5dfac58024d323ca8d0a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#164-175","gmt_create":"2026-04-23T20:31:36.618327+08:00","gmt_modified":"2026-04-23T20:31:36.618327+08:00"},{"id":585,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"15b8ebf74b0a5dfac58024d323ca8d0a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 164-175","gmt_create":"2026-04-23T20:31:36.618609+08:00","gmt_modified":"2026-04-23T20:31:36.618609+08:00"},{"id":586,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:31:50.473102+08:00","gmt_modified":"2026-04-23T20:31:50.473102+08:00"},{"id":587,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:31:50.473614+08:00","gmt_modified":"2026-04-23T20:31:50.473614+08:00"},{"id":588,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:31:50.474171+08:00","gmt_modified":"2026-04-23T20:31:50.474171+08:00"},{"id":589,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:31:50.474429+08:00","gmt_modified":"2026-04-23T20:31:50.474429+08:00"},{"id":590,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:31:50.474658+08:00","gmt_modified":"2026-04-23T20:31:50.474658+08:00"},{"id":591,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:31:50.474883+08:00","gmt_modified":"2026-04-23T20:31:50.474883+08:00"},{"id":592,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:31:50.475158+08:00","gmt_modified":"2026-04-23T20:31:50.475158+08:00"},{"id":593,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-04-23T20:31:50.475559+08:00","gmt_modified":"2026-04-23T20:31:50.475559+08:00"},{"id":594,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:31:50.475799+08:00","gmt_modified":"2026-04-23T20:31:50.475799+08:00"},{"id":595,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:31:50.47602+08:00","gmt_modified":"2026-04-23T20:31:50.47602+08:00"},{"id":596,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"42ff5383133d176cec9eb88682483be3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citations.py","gmt_create":"2026-04-23T20:31:50.476237+08:00","gmt_modified":"2026-04-23T20:31:50.476237+08:00"},{"id":597,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:31:50.476528+08:00","gmt_modified":"2026-04-23T20:31:50.476528+08:00"},{"id":598,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"bcfade20d923c8efa713808ca9af94ca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#10-38","gmt_create":"2026-04-23T20:31:50.476982+08:00","gmt_modified":"2026-04-23T20:31:50.476982+08:00"},{"id":599,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"bcfade20d923c8efa713808ca9af94ca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:50.477216+08:00","gmt_modified":"2026-04-23T20:31:50.477216+08:00"},{"id":600,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"ca7e1232fbba5fb75e04ab8e491bfbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#10-38","gmt_create":"2026-04-23T20:31:50.477565+08:00","gmt_modified":"2026-04-23T20:31:50.477565+08:00"},{"id":601,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"ca7e1232fbba5fb75e04ab8e491bfbd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:50.477978+08:00","gmt_modified":"2026-04-23T20:31:50.477978+08:00"},{"id":602,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#10-38","gmt_create":"2026-04-23T20:31:50.478592+08:00","gmt_modified":"2026-04-23T20:31:50.478592+08:00"},{"id":603,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:31:50.479311+08:00","gmt_modified":"2026-04-23T20:31:50.479311+08:00"},{"id":604,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"9720b93ed7247efb685e2825e5f964bf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-176","gmt_create":"2026-04-23T20:31:50.479856+08:00","gmt_modified":"2026-04-23T20:31:50.479856+08:00"},{"id":605,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"9720b93ed7247efb685e2825e5f964bf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-176","gmt_create":"2026-04-23T20:31:50.48037+08:00","gmt_modified":"2026-04-23T20:31:50.48037+08:00"},{"id":606,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"0d226400124ba891a46f59c36781ccd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-23","gmt_create":"2026-04-23T20:31:50.481311+08:00","gmt_modified":"2026-04-23T20:31:50.481311+08:00"},{"id":607,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"0d226400124ba891a46f59c36781ccd8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-23","gmt_create":"2026-04-23T20:31:50.481625+08:00","gmt_modified":"2026-04-23T20:31:50.481625+08:00"},{"id":608,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"412695e5de2014514a8f62f98c573656","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#1-41","gmt_create":"2026-04-23T20:31:50.482236+08:00","gmt_modified":"2026-04-23T20:31:50.482236+08:00"},{"id":609,"source_id":"e9b52adbec3c07cf021e488dd3f99ab4","target_id":"412695e5de2014514a8f62f98c573656","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-23T20:31:50.483281+08:00","gmt_modified":"2026-04-23T20:31:50.483281+08:00"},{"id":610,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:31:50.483853+08:00","gmt_modified":"2026-04-23T20:31:50.483854+08:00"},{"id":611,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"485e15eb30a5b08da38a628c9dd5053e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#16-77","gmt_create":"2026-04-23T20:31:50.48646+08:00","gmt_modified":"2026-04-23T20:31:50.48646+08:00"},{"id":612,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"485e15eb30a5b08da38a628c9dd5053e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-77","gmt_create":"2026-04-23T20:31:50.486841+08:00","gmt_modified":"2026-04-23T20:31:50.486841+08:00"},{"id":613,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:31:50.487399+08:00","gmt_modified":"2026-04-23T20:31:50.487399+08:00"},{"id":614,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:31:50.488281+08:00","gmt_modified":"2026-04-23T20:31:50.488281+08:00"},{"id":615,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-33","gmt_create":"2026-04-23T20:31:50.488807+08:00","gmt_modified":"2026-04-23T20:31:50.488807+08:00"},{"id":616,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:31:50.489038+08:00","gmt_modified":"2026-04-23T20:31:50.489038+08:00"},{"id":617,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"5c3f336b5a7b4af4cc2f2ac183539218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-145","gmt_create":"2026-04-23T20:31:50.491706+08:00","gmt_modified":"2026-04-23T20:31:50.491706+08:00"},{"id":618,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"5c3f336b5a7b4af4cc2f2ac183539218","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-145","gmt_create":"2026-04-23T20:31:50.492445+08:00","gmt_modified":"2026-04-23T20:31:50.492445+08:00"},{"id":619,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"3894c1ed9dca2ebf2359f40ebdb1959e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#147-174","gmt_create":"2026-04-23T20:31:50.493129+08:00","gmt_modified":"2026-04-23T20:31:50.493129+08:00"},{"id":620,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"3894c1ed9dca2ebf2359f40ebdb1959e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 147-174","gmt_create":"2026-04-23T20:31:50.493716+08:00","gmt_modified":"2026-04-23T20:31:50.493716+08:00"},{"id":621,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:31:50.494347+08:00","gmt_modified":"2026-04-23T20:31:50.494348+08:00"},{"id":622,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-109","gmt_create":"2026-04-23T20:31:50.496521+08:00","gmt_modified":"2026-04-23T20:31:50.496521+08:00"},{"id":623,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-109","gmt_create":"2026-04-23T20:31:50.496915+08:00","gmt_modified":"2026-04-23T20:31:50.496915+08:00"},{"id":624,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"5f893f5078aa8e549284feb057aa45da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-29","gmt_create":"2026-04-23T20:31:50.499115+08:00","gmt_modified":"2026-04-23T20:31:50.499115+08:00"},{"id":625,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"5f893f5078aa8e549284feb057aa45da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-29","gmt_create":"2026-04-23T20:31:50.49944+08:00","gmt_modified":"2026-04-23T20:31:50.49944+08:00"},{"id":626,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:31:50.50016+08:00","gmt_modified":"2026-04-23T20:31:50.50016+08:00"},{"id":627,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e0b68d2d24760689a0f4f00dfee5f9f2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#28-76","gmt_create":"2026-04-23T20:31:50.500908+08:00","gmt_modified":"2026-04-23T20:31:50.500908+08:00"},{"id":628,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"e0b68d2d24760689a0f4f00dfee5f9f2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-76","gmt_create":"2026-04-23T20:31:50.501388+08:00","gmt_modified":"2026-04-23T20:31:50.501388+08:00"},{"id":629,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e9b98ae83632342d8e06cde39e9c9462","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#105-137","gmt_create":"2026-04-23T20:31:50.502229+08:00","gmt_modified":"2026-04-23T20:31:50.502229+08:00"},{"id":630,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"e9b98ae83632342d8e06cde39e9c9462","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 105-137","gmt_create":"2026-04-23T20:31:50.502758+08:00","gmt_modified":"2026-04-23T20:31:50.502758+08:00"},{"id":631,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:31:50.503532+08:00","gmt_modified":"2026-04-23T20:31:50.503532+08:00"},{"id":632,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#23-93","gmt_create":"2026-04-23T20:31:50.504205+08:00","gmt_modified":"2026-04-23T20:31:50.504206+08:00"},{"id":633,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-109","gmt_create":"2026-04-23T20:31:50.504719+08:00","gmt_modified":"2026-04-23T20:31:50.504719+08:00"},{"id":634,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 90-109","gmt_create":"2026-04-23T20:31:50.505358+08:00","gmt_modified":"2026-04-23T20:31:50.505358+08:00"},{"id":635,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:30.005285+08:00","gmt_modified":"2026-04-23T20:33:30.005285+08:00"},{"id":636,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:30.006785+08:00","gmt_modified":"2026-04-23T20:33:30.006785+08:00"},{"id":637,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:30.008852+08:00","gmt_modified":"2026-04-23T20:33:30.008852+08:00"},{"id":638,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:30.010802+08:00","gmt_modified":"2026-04-23T20:33:30.010803+08:00"},{"id":639,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:30.011496+08:00","gmt_modified":"2026-04-23T20:33:30.011496+08:00"},{"id":640,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T20:33:30.012521+08:00","gmt_modified":"2026-04-23T20:33:30.012521+08:00"},{"id":641,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:33:30.013288+08:00","gmt_modified":"2026-04-23T20:33:30.013288+08:00"},{"id":642,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:30.014048+08:00","gmt_modified":"2026-04-23T20:33:30.014048+08:00"},{"id":643,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:30.014998+08:00","gmt_modified":"2026-04-23T20:33:30.014998+08:00"},{"id":644,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:30.015593+08:00","gmt_modified":"2026-04-23T20:33:30.015593+08:00"},{"id":645,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:30.016186+08:00","gmt_modified":"2026-04-23T20:33:30.016187+08:00"},{"id":646,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:30.017118+08:00","gmt_modified":"2026-04-23T20:33:30.017118+08:00"},{"id":647,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-04-23T20:33:30.017481+08:00","gmt_modified":"2026-04-23T20:33:30.017481+08:00"},{"id":648,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:30.018279+08:00","gmt_modified":"2026-04-23T20:33:30.018279+08:00"},{"id":649,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T20:33:30.019076+08:00","gmt_modified":"2026-04-23T20:33:30.019076+08:00"},{"id":650,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T20:33:30.020384+08:00","gmt_modified":"2026-04-23T20:33:30.020384+08:00"},{"id":651,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"6e054d9a78c0c8c9da8dec4c4bda62ab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-28","gmt_create":"2026-04-23T20:33:30.021894+08:00","gmt_modified":"2026-04-23T20:33:30.021895+08:00"},{"id":652,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"6e054d9a78c0c8c9da8dec4c4bda62ab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-28","gmt_create":"2026-04-23T20:33:30.022319+08:00","gmt_modified":"2026-04-23T20:33:30.022319+08:00"},{"id":653,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:33:30.039084+08:00","gmt_modified":"2026-04-23T20:33:30.039085+08:00"},{"id":654,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:30.042279+08:00","gmt_modified":"2026-04-23T20:33:30.042279+08:00"},{"id":655,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:33:30.043781+08:00","gmt_modified":"2026-04-23T20:33:30.043781+08:00"},{"id":656,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T20:33:30.048591+08:00","gmt_modified":"2026-04-23T20:33:30.048591+08:00"},{"id":657,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:30.049875+08:00","gmt_modified":"2026-04-23T20:33:30.049875+08:00"},{"id":658,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T20:33:30.052505+08:00","gmt_modified":"2026-04-23T20:33:30.052505+08:00"},{"id":659,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T20:33:30.054452+08:00","gmt_modified":"2026-04-23T20:33:30.054452+08:00"},{"id":660,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9c16a069e5154660bfdfa48f3518fc6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-38","gmt_create":"2026-04-23T20:33:30.056033+08:00","gmt_modified":"2026-04-23T20:33:30.056033+08:00"},{"id":661,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"9c16a069e5154660bfdfa48f3518fc6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-38","gmt_create":"2026-04-23T20:33:30.056759+08:00","gmt_modified":"2026-04-23T20:33:30.056759+08:00"},{"id":662,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#30-90","gmt_create":"2026-04-23T20:33:30.060127+08:00","gmt_modified":"2026-04-23T20:33:30.060127+08:00"},{"id":663,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T20:33:30.06165+08:00","gmt_modified":"2026-04-23T20:33:30.06165+08:00"},{"id":664,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-48","gmt_create":"2026-04-23T20:33:30.063084+08:00","gmt_modified":"2026-04-23T20:33:30.063084+08:00"},{"id":665,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-48","gmt_create":"2026-04-23T20:33:30.063941+08:00","gmt_modified":"2026-04-23T20:33:30.063941+08:00"},{"id":666,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-48","gmt_create":"2026-04-23T20:33:30.065013+08:00","gmt_modified":"2026-04-23T20:33:30.065013+08:00"},{"id":667,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-48","gmt_create":"2026-04-23T20:33:30.066091+08:00","gmt_modified":"2026-04-23T20:33:30.066091+08:00"},{"id":668,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"72f6d334026866e8a61d2ffb1d83370a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-100","gmt_create":"2026-04-23T20:33:30.06977+08:00","gmt_modified":"2026-04-23T20:33:30.06977+08:00"},{"id":669,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"72f6d334026866e8a61d2ffb1d83370a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-100","gmt_create":"2026-04-23T20:33:30.070839+08:00","gmt_modified":"2026-04-23T20:33:30.070839+08:00"},{"id":670,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#122-146","gmt_create":"2026-04-23T20:33:30.07226+08:00","gmt_modified":"2026-04-23T20:33:30.07226+08:00"},{"id":671,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:33:30.076075+08:00","gmt_modified":"2026-04-23T20:33:30.076076+08:00"},{"id":672,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-48","gmt_create":"2026-04-23T20:33:30.080882+08:00","gmt_modified":"2026-04-23T20:33:30.080882+08:00"},{"id":673,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1d84b9a7eb013882953a2d1d948299e4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#126-197","gmt_create":"2026-04-23T20:33:30.082996+08:00","gmt_modified":"2026-04-23T20:33:30.082997+08:00"},{"id":674,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"1d84b9a7eb013882953a2d1d948299e4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 126-197","gmt_create":"2026-04-23T20:33:30.084021+08:00","gmt_modified":"2026-04-23T20:33:30.084021+08:00"},{"id":675,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-48","gmt_create":"2026-04-23T20:33:30.08518+08:00","gmt_modified":"2026-04-23T20:33:30.085181+08:00"},{"id":676,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ba687f2c64aff92b3906658359ed953a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#124-195","gmt_create":"2026-04-23T20:33:30.086912+08:00","gmt_modified":"2026-04-23T20:33:30.086913+08:00"},{"id":677,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"ba687f2c64aff92b3906658359ed953a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 124-195","gmt_create":"2026-04-23T20:33:30.087917+08:00","gmt_modified":"2026-04-23T20:33:30.087917+08:00"},{"id":678,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"52ee729b02c992c689522c7956c14128","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#57-62","gmt_create":"2026-04-23T20:33:30.090606+08:00","gmt_modified":"2026-04-23T20:33:30.090606+08:00"},{"id":679,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"52ee729b02c992c689522c7956c14128","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-62","gmt_create":"2026-04-23T20:33:30.092747+08:00","gmt_modified":"2026-04-23T20:33:30.092747+08:00"},{"id":680,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"c9e32b7324cce60c8887deb8404ee759","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#107-112","gmt_create":"2026-04-23T20:33:30.094246+08:00","gmt_modified":"2026-04-23T20:33:30.094246+08:00"},{"id":681,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"c9e32b7324cce60c8887deb8404ee759","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 107-112","gmt_create":"2026-04-23T20:33:30.095189+08:00","gmt_modified":"2026-04-23T20:33:30.095189+08:00"},{"id":682,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-04-23T20:33:30.096673+08:00","gmt_modified":"2026-04-23T20:33:30.096673+08:00"},{"id":683,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"8355d3821337334caee57a75dc8c8865","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#116-130","gmt_create":"2026-04-23T20:33:30.098422+08:00","gmt_modified":"2026-04-23T20:33:30.098422+08:00"},{"id":684,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"8355d3821337334caee57a75dc8c8865","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 116-130","gmt_create":"2026-04-23T20:33:30.099427+08:00","gmt_modified":"2026-04-23T20:33:30.099427+08:00"},{"id":685,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"4fe27d4d1323b500e72d870aa6212a1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#13-20","gmt_create":"2026-04-23T20:33:30.101771+08:00","gmt_modified":"2026-04-23T20:33:30.101771+08:00"},{"id":686,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"4fe27d4d1323b500e72d870aa6212a1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-20","gmt_create":"2026-04-23T20:33:30.102515+08:00","gmt_modified":"2026-04-23T20:33:30.102515+08:00"},{"id":687,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-157","gmt_create":"2026-04-23T20:33:30.103598+08:00","gmt_modified":"2026-04-23T20:33:30.103599+08:00"},{"id":688,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-157","gmt_create":"2026-04-23T20:33:30.104105+08:00","gmt_modified":"2026-04-23T20:33:30.104105+08:00"},{"id":689,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1ee5153c867fc6e9d277a3067963a1fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#32-38","gmt_create":"2026-04-23T20:33:30.105113+08:00","gmt_modified":"2026-04-23T20:33:30.105113+08:00"},{"id":690,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"1ee5153c867fc6e9d277a3067963a1fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-38","gmt_create":"2026-04-23T20:33:30.105627+08:00","gmt_modified":"2026-04-23T20:33:30.105627+08:00"},{"id":691,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#50-54","gmt_create":"2026-04-23T20:33:30.106672+08:00","gmt_modified":"2026-04-23T20:33:30.106672+08:00"},{"id":692,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 50-54","gmt_create":"2026-04-23T20:33:30.107651+08:00","gmt_modified":"2026-04-23T20:33:30.107651+08:00"},{"id":693,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#36-38","gmt_create":"2026-04-23T20:33:30.109238+08:00","gmt_modified":"2026-04-23T20:33:30.109238+08:00"},{"id":694,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1a3351698ecc7cd4e508b7a792804fc4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#302-309","gmt_create":"2026-04-23T20:33:30.111966+08:00","gmt_modified":"2026-04-23T20:33:30.111966+08:00"},{"id":695,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1a3351698ecc7cd4e508b7a792804fc4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 302-309","gmt_create":"2026-04-23T20:33:30.112959+08:00","gmt_modified":"2026-04-23T20:33:30.11296+08:00"},{"id":696,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e3e9710c7eead933c936519395f792e0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#44-49","gmt_create":"2026-04-23T20:33:30.114604+08:00","gmt_modified":"2026-04-23T20:33:30.114605+08:00"},{"id":697,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e3e9710c7eead933c936519395f792e0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-49","gmt_create":"2026-04-23T20:33:30.115247+08:00","gmt_modified":"2026-04-23T20:33:30.115247+08:00"},{"id":698,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7","gmt_create":"2026-04-23T20:33:30.116587+08:00","gmt_modified":"2026-04-23T20:33:30.116587+08:00"},{"id":699,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a4143cc29b14f1f5bc75a5e021690666","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#23-31","gmt_create":"2026-04-23T20:33:30.117646+08:00","gmt_modified":"2026-04-23T20:33:30.117646+08:00"},{"id":700,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"a4143cc29b14f1f5bc75a5e021690666","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-31","gmt_create":"2026-04-23T20:33:30.118764+08:00","gmt_modified":"2026-04-23T20:33:30.118764+08:00"},{"id":701,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"7192cfda5508e7587efd91d26cf1f018","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#23-31","gmt_create":"2026-04-23T20:33:30.120253+08:00","gmt_modified":"2026-04-23T20:33:30.120253+08:00"},{"id":702,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"7192cfda5508e7587efd91d26cf1f018","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-31","gmt_create":"2026-04-23T20:33:30.121853+08:00","gmt_modified":"2026-04-23T20:33:30.121853+08:00"},{"id":703,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#211-227","gmt_create":"2026-04-23T20:33:30.1234+08:00","gmt_modified":"2026-04-23T20:33:30.1234+08:00"},{"id":704,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 211-227","gmt_create":"2026-04-23T20:33:30.125433+08:00","gmt_modified":"2026-04-23T20:33:30.125433+08:00"},{"id":705,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"fb5276346dcc4e7044d8765a8572e7a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-16","gmt_create":"2026-04-23T20:33:30.128657+08:00","gmt_modified":"2026-04-23T20:33:30.128657+08:00"},{"id":706,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"fb5276346dcc4e7044d8765a8572e7a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-16","gmt_create":"2026-04-23T20:33:30.129814+08:00","gmt_modified":"2026-04-23T20:33:30.129814+08:00"},{"id":707,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:37.259749+08:00","gmt_modified":"2026-04-23T20:33:37.259749+08:00"},{"id":708,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:37.26107+08:00","gmt_modified":"2026-04-23T20:33:37.26107+08:00"},{"id":709,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:37.261714+08:00","gmt_modified":"2026-04-23T20:33:37.261714+08:00"},{"id":710,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:37.262532+08:00","gmt_modified":"2026-04-23T20:33:37.262532+08:00"},{"id":711,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:33:37.263665+08:00","gmt_modified":"2026-04-23T20:33:37.263665+08:00"},{"id":712,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"404f6d0765a8c6e77e33b7fc21b377a4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/doubao.py","gmt_create":"2026-04-23T20:33:37.26425+08:00","gmt_modified":"2026-04-23T20:33:37.26425+08:00"},{"id":713,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"303e80519e946904d1cb3ac32cbb0814","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/qingyan.py","gmt_create":"2026-04-23T20:33:37.265278+08:00","gmt_modified":"2026-04-23T20:33:37.265278+08:00"},{"id":714,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5af7301fe056fc3d10820d820e8ad777","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tiangong.py","gmt_create":"2026-04-23T20:33:37.265809+08:00","gmt_modified":"2026-04-23T20:33:37.265809+08:00"},{"id":715,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"0e38ad5d2d3daaad08c9302df8805b15","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/xinghuo.py","gmt_create":"2026-04-23T20:33:37.266496+08:00","gmt_modified":"2026-04-23T20:33:37.266496+08:00"},{"id":716,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:33:37.267203+08:00","gmt_modified":"2026-04-23T20:33:37.267203+08:00"},{"id":717,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:37.268722+08:00","gmt_modified":"2026-04-23T20:33:37.268722+08:00"},{"id":718,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:33:37.269288+08:00","gmt_modified":"2026-04-23T20:33:37.269288+08:00"},{"id":719,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:37.270139+08:00","gmt_modified":"2026-04-23T20:33:37.270139+08:00"},{"id":720,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:33:37.273632+08:00","gmt_modified":"2026-04-23T20:33:37.273632+08:00"},{"id":721,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:37.275218+08:00","gmt_modified":"2026-04-23T20:33:37.275218+08:00"},{"id":722,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:37.276269+08:00","gmt_modified":"2026-04-23T20:33:37.27627+08:00"},{"id":723,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:33:37.277294+08:00","gmt_modified":"2026-04-23T20:33:37.277294+08:00"},{"id":724,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:37.278423+08:00","gmt_modified":"2026-04-23T20:33:37.278423+08:00"},{"id":725,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-04-23T20:33:37.279079+08:00","gmt_modified":"2026-04-23T20:33:37.279079+08:00"},{"id":726,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-23T20:33:37.279629+08:00","gmt_modified":"2026-04-23T20:33:37.27963+08:00"},{"id":727,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T20:33:37.280454+08:00","gmt_modified":"2026-04-23T20:33:37.280454+08:00"},{"id":728,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:33:37.281512+08:00","gmt_modified":"2026-04-23T20:33:37.281513+08:00"},{"id":729,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"482d573f97b482b99bcde1c399eceb73","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-108","gmt_create":"2026-04-23T20:33:37.281875+08:00","gmt_modified":"2026-04-23T20:33:37.281876+08:00"},{"id":730,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"482d573f97b482b99bcde1c399eceb73","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 90-108","gmt_create":"2026-04-23T20:33:37.28285+08:00","gmt_modified":"2026-04-23T20:33:37.28285+08:00"},{"id":731,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-269","gmt_create":"2026-04-23T20:33:37.283208+08:00","gmt_modified":"2026-04-23T20:33:37.283208+08:00"},{"id":732,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:37.283598+08:00","gmt_modified":"2026-04-23T20:33:37.283598+08:00"},{"id":733,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-123","gmt_create":"2026-04-23T20:33:37.284031+08:00","gmt_modified":"2026-04-23T20:33:37.284031+08:00"},{"id":734,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-330","gmt_create":"2026-04-23T20:33:37.284881+08:00","gmt_modified":"2026-04-23T20:33:37.284881+08:00"},{"id":735,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:33:37.285439+08:00","gmt_modified":"2026-04-23T20:33:37.285439+08:00"},{"id":736,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"56f44cc97867cee3e5663424134d6072","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#1-37","gmt_create":"2026-04-23T20:33:37.285889+08:00","gmt_modified":"2026-04-23T20:33:37.285889+08:00"},{"id":737,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"56f44cc97867cee3e5663424134d6072","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:33:37.286195+08:00","gmt_modified":"2026-04-23T20:33:37.286195+08:00"},{"id":738,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"2e326ef8322619f1e8b3873022cb0437","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#1-37","gmt_create":"2026-04-23T20:33:37.286846+08:00","gmt_modified":"2026-04-23T20:33:37.286846+08:00"},{"id":739,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"2e326ef8322619f1e8b3873022cb0437","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:33:37.287299+08:00","gmt_modified":"2026-04-23T20:33:37.287299+08:00"},{"id":740,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#1-38","gmt_create":"2026-04-23T20:33:37.28771+08:00","gmt_modified":"2026-04-23T20:33:37.287711+08:00"},{"id":741,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#1-38","gmt_create":"2026-04-23T20:33:37.288659+08:00","gmt_modified":"2026-04-23T20:33:37.288659+08:00"},{"id":742,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#1-38","gmt_create":"2026-04-23T20:33:37.290497+08:00","gmt_modified":"2026-04-23T20:33:37.290498+08:00"},{"id":743,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#1-38","gmt_create":"2026-04-23T20:33:37.292345+08:00","gmt_modified":"2026-04-23T20:33:37.292345+08:00"},{"id":744,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#1-38","gmt_create":"2026-04-23T20:33:37.293708+08:00","gmt_modified":"2026-04-23T20:33:37.293708+08:00"},{"id":745,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:33:37.2944+08:00","gmt_modified":"2026-04-23T20:33:37.2944+08:00"},{"id":746,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4cac57dbc530f0335c913ec5725dfa4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-121","gmt_create":"2026-04-23T20:33:37.295331+08:00","gmt_modified":"2026-04-23T20:33:37.295331+08:00"},{"id":747,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"4cac57dbc530f0335c913ec5725dfa4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-121","gmt_create":"2026-04-23T20:33:37.296239+08:00","gmt_modified":"2026-04-23T20:33:37.296239+08:00"},{"id":748,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:37.296858+08:00","gmt_modified":"2026-04-23T20:33:37.296858+08:00"},{"id":749,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:33:37.297624+08:00","gmt_modified":"2026-04-23T20:33:37.297624+08:00"},{"id":750,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:33:37.298765+08:00","gmt_modified":"2026-04-23T20:33:37.298765+08:00"},{"id":751,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-23T20:33:37.299752+08:00","gmt_modified":"2026-04-23T20:33:37.299752+08:00"},{"id":752,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:37.30067+08:00","gmt_modified":"2026-04-23T20:33:37.30067+08:00"},{"id":753,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"db174cfe219fc84d0dd26529f047b1d0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-330","gmt_create":"2026-04-23T20:33:37.304109+08:00","gmt_modified":"2026-04-23T20:33:37.304109+08:00"},{"id":754,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"db174cfe219fc84d0dd26529f047b1d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-330","gmt_create":"2026-04-23T20:33:37.304836+08:00","gmt_modified":"2026-04-23T20:33:37.304836+08:00"},{"id":755,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f36452f78aabfb0c46da03bbe25dff06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-295","gmt_create":"2026-04-23T20:33:37.307629+08:00","gmt_modified":"2026-04-23T20:33:37.307629+08:00"},{"id":756,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"f36452f78aabfb0c46da03bbe25dff06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-295","gmt_create":"2026-04-23T20:33:37.308258+08:00","gmt_modified":"2026-04-23T20:33:37.308258+08:00"},{"id":757,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:33:37.310127+08:00","gmt_modified":"2026-04-23T20:33:37.310127+08:00"},{"id":758,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#16-33","gmt_create":"2026-04-23T20:33:37.31061+08:00","gmt_modified":"2026-04-23T20:33:37.31061+08:00"},{"id":759,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:33:37.311106+08:00","gmt_modified":"2026-04-23T20:33:37.311106+08:00"},{"id":760,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-33","gmt_create":"2026-04-23T20:33:37.311558+08:00","gmt_modified":"2026-04-23T20:33:37.311558+08:00"},{"id":761,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:33:37.319146+08:00","gmt_modified":"2026-04-23T20:33:37.319146+08:00"},{"id":762,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-33","gmt_create":"2026-04-23T20:33:37.320166+08:00","gmt_modified":"2026-04-23T20:33:37.320166+08:00"},{"id":763,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9d352899554ab41b65b2e9f32558d811","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#39-113","gmt_create":"2026-04-23T20:33:37.321322+08:00","gmt_modified":"2026-04-23T20:33:37.321322+08:00"},{"id":764,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"9d352899554ab41b65b2e9f32558d811","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-113","gmt_create":"2026-04-23T20:33:37.322276+08:00","gmt_modified":"2026-04-23T20:33:37.322276+08:00"},{"id":765,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b1ee5a992230844ba898765be63f7b27","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#32-133","gmt_create":"2026-04-23T20:33:37.323119+08:00","gmt_modified":"2026-04-23T20:33:37.323119+08:00"},{"id":766,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"b1ee5a992230844ba898765be63f7b27","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-133","gmt_create":"2026-04-23T20:33:37.323615+08:00","gmt_modified":"2026-04-23T20:33:37.323615+08:00"},{"id":767,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"cb098a3cd32339e99f755dfd0fc35b5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#6-127","gmt_create":"2026-04-23T20:33:37.324259+08:00","gmt_modified":"2026-04-23T20:33:37.324259+08:00"},{"id":768,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"cb098a3cd32339e99f755dfd0fc35b5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-127","gmt_create":"2026-04-23T20:33:37.32508+08:00","gmt_modified":"2026-04-23T20:33:37.32508+08:00"},{"id":769,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#145-158","gmt_create":"2026-04-23T20:33:37.325915+08:00","gmt_modified":"2026-04-23T20:33:37.325915+08:00"},{"id":770,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 145-158","gmt_create":"2026-04-23T20:33:37.327012+08:00","gmt_modified":"2026-04-23T20:33:37.327012+08:00"},{"id":771,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4e9b3d0e94282f4bc6fa500f4eed61a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#135-159","gmt_create":"2026-04-23T20:33:37.327853+08:00","gmt_modified":"2026-04-23T20:33:37.327853+08:00"},{"id":772,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"4e9b3d0e94282f4bc6fa500f4eed61a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 135-159","gmt_create":"2026-04-23T20:33:37.328872+08:00","gmt_modified":"2026-04-23T20:33:37.328872+08:00"},{"id":773,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8e3201561a9dd9a06ee3bf68ffdb3f99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#39-109","gmt_create":"2026-04-23T20:33:37.32989+08:00","gmt_modified":"2026-04-23T20:33:37.32989+08:00"},{"id":774,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"8e3201561a9dd9a06ee3bf68ffdb3f99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-109","gmt_create":"2026-04-23T20:33:37.33132+08:00","gmt_modified":"2026-04-23T20:33:37.33132+08:00"},{"id":775,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c3a417be3d61f5bcd3fbf976e0c4f15a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#33-121","gmt_create":"2026-04-23T20:33:37.336944+08:00","gmt_modified":"2026-04-23T20:33:37.336944+08:00"},{"id":776,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"c3a417be3d61f5bcd3fbf976e0c4f15a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-121","gmt_create":"2026-04-23T20:33:37.337655+08:00","gmt_modified":"2026-04-23T20:33:37.337655+08:00"},{"id":777,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:37.339169+08:00","gmt_modified":"2026-04-23T20:33:37.339169+08:00"},{"id":778,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7ce954ed7d3bc4dcf78630124cc0dd88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#264-295","gmt_create":"2026-04-23T20:33:37.34124+08:00","gmt_modified":"2026-04-23T20:33:37.34124+08:00"},{"id":779,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"7ce954ed7d3bc4dcf78630124cc0dd88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 264-295","gmt_create":"2026-04-23T20:33:37.342433+08:00","gmt_modified":"2026-04-23T20:33:37.342433+08:00"},{"id":780,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-35","gmt_create":"2026-04-23T20:33:37.346038+08:00","gmt_modified":"2026-04-23T20:33:37.346038+08:00"},{"id":781,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-35","gmt_create":"2026-04-23T20:33:37.346577+08:00","gmt_modified":"2026-04-23T20:33:37.346577+08:00"},{"id":782,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-32","gmt_create":"2026-04-23T20:33:37.352671+08:00","gmt_modified":"2026-04-23T20:33:37.352671+08:00"},{"id":783,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-32","gmt_create":"2026-04-23T20:33:37.354355+08:00","gmt_modified":"2026-04-23T20:33:37.354355+08:00"},{"id":784,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-32","gmt_create":"2026-04-23T20:33:37.355472+08:00","gmt_modified":"2026-04-23T20:33:37.355472+08:00"},{"id":785,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-32","gmt_create":"2026-04-23T20:33:37.357613+08:00","gmt_modified":"2026-04-23T20:33:37.357613+08:00"},{"id":786,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:33:37.358273+08:00","gmt_modified":"2026-04-23T20:33:37.358273+08:00"},{"id":787,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5563b3bd56550648dc70302c1762ce5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#18-29","gmt_create":"2026-04-23T20:33:37.360657+08:00","gmt_modified":"2026-04-23T20:33:37.360657+08:00"},{"id":788,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"5563b3bd56550648dc70302c1762ce5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-29","gmt_create":"2026-04-23T20:33:37.361776+08:00","gmt_modified":"2026-04-23T20:33:37.361776+08:00"},{"id":789,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"91852ef8dcc844a2f85e9fce0227ab74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#18-29","gmt_create":"2026-04-23T20:33:37.363109+08:00","gmt_modified":"2026-04-23T20:33:37.363109+08:00"},{"id":790,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"91852ef8dcc844a2f85e9fce0227ab74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-29","gmt_create":"2026-04-23T20:33:37.363811+08:00","gmt_modified":"2026-04-23T20:33:37.363811+08:00"},{"id":791,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"1b46fab9e22f53db30ead5677d03e3e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#11-16","gmt_create":"2026-04-23T20:33:37.364819+08:00","gmt_modified":"2026-04-23T20:33:37.364819+08:00"},{"id":792,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1b46fab9e22f53db30ead5677d03e3e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-16","gmt_create":"2026-04-23T20:33:37.365554+08:00","gmt_modified":"2026-04-23T20:33:37.365554+08:00"},{"id":793,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:33:37.36634+08:00","gmt_modified":"2026-04-23T20:33:37.366341+08:00"},{"id":794,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4a2fa09aa3a948dec5ef8ba873b0e716","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#14-42","gmt_create":"2026-04-23T20:33:37.367379+08:00","gmt_modified":"2026-04-23T20:33:37.367379+08:00"},{"id":795,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"4a2fa09aa3a948dec5ef8ba873b0e716","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-42","gmt_create":"2026-04-23T20:33:37.368233+08:00","gmt_modified":"2026-04-23T20:33:37.368233+08:00"},{"id":796,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:33:57.518077+08:00","gmt_modified":"2026-04-23T20:33:57.518077+08:00"},{"id":797,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-04-23T20:33:57.518453+08:00","gmt_modified":"2026-04-23T20:33:57.518454+08:00"},{"id":798,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-23T20:33:57.519644+08:00","gmt_modified":"2026-04-23T20:33:57.519644+08:00"},{"id":799,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:57.521079+08:00","gmt_modified":"2026-04-23T20:33:57.521079+08:00"},{"id":800,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:57.522061+08:00","gmt_modified":"2026-04-23T20:33:57.522061+08:00"},{"id":801,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:33:57.523189+08:00","gmt_modified":"2026-04-23T20:33:57.523189+08:00"},{"id":802,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-23T20:33:57.52383+08:00","gmt_modified":"2026-04-23T20:33:57.52383+08:00"},{"id":803,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:57.524563+08:00","gmt_modified":"2026-04-23T20:33:57.524563+08:00"},{"id":804,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:33:57.525774+08:00","gmt_modified":"2026-04-23T20:33:57.525774+08:00"},{"id":805,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:57.526492+08:00","gmt_modified":"2026-04-23T20:33:57.526492+08:00"},{"id":806,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:57.527326+08:00","gmt_modified":"2026-04-23T20:33:57.527326+08:00"},{"id":807,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:57.527983+08:00","gmt_modified":"2026-04-23T20:33:57.527983+08:00"},{"id":808,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:57.529144+08:00","gmt_modified":"2026-04-23T20:33:57.529144+08:00"},{"id":809,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:57.529998+08:00","gmt_modified":"2026-04-23T20:33:57.529998+08:00"},{"id":810,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:57.530659+08:00","gmt_modified":"2026-04-23T20:33:57.530659+08:00"},{"id":811,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:57.531953+08:00","gmt_modified":"2026-04-23T20:33:57.531953+08:00"},{"id":812,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-04-23T20:33:57.532681+08:00","gmt_modified":"2026-04-23T20:33:57.532681+08:00"},{"id":813,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"80a0429cc47931de27ddb17a62b8dd9c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_business_flow.py","gmt_create":"2026-04-23T20:33:57.533708+08:00","gmt_modified":"2026-04-23T20:33:57.533708+08:00"},{"id":814,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-109","gmt_create":"2026-04-23T20:33:57.534482+08:00","gmt_modified":"2026-04-23T20:33:57.534482+08:00"},{"id":815,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e7afbab5932c93c3469f1a225e6c7156","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-55","gmt_create":"2026-04-23T20:33:57.535515+08:00","gmt_modified":"2026-04-23T20:33:57.535515+08:00"},{"id":816,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"e7afbab5932c93c3469f1a225e6c7156","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-55","gmt_create":"2026-04-23T20:33:57.536318+08:00","gmt_modified":"2026-04-23T20:33:57.536318+08:00"},{"id":817,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a0eac56d622a2fff529bc2b796064bcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#1-94","gmt_create":"2026-04-23T20:33:57.537094+08:00","gmt_modified":"2026-04-23T20:33:57.537094+08:00"},{"id":818,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"a0eac56d622a2fff529bc2b796064bcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-94","gmt_create":"2026-04-23T20:33:57.537769+08:00","gmt_modified":"2026-04-23T20:33:57.53777+08:00"},{"id":819,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"174be58163b6f72b4cd4a493f3463ce4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#1-52","gmt_create":"2026-04-23T20:33:57.53855+08:00","gmt_modified":"2026-04-23T20:33:57.53855+08:00"},{"id":820,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"174be58163b6f72b4cd4a493f3463ce4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-52","gmt_create":"2026-04-23T20:33:57.53965+08:00","gmt_modified":"2026-04-23T20:33:57.53965+08:00"},{"id":821,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:57.54057+08:00","gmt_modified":"2026-04-23T20:33:57.54057+08:00"},{"id":822,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:33:57.541654+08:00","gmt_modified":"2026-04-23T20:33:57.541654+08:00"},{"id":823,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:33:57.543056+08:00","gmt_modified":"2026-04-23T20:33:57.543056+08:00"},{"id":824,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-04-23T20:33:57.543958+08:00","gmt_modified":"2026-04-23T20:33:57.543958+08:00"},{"id":825,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-23T20:33:57.544974+08:00","gmt_modified":"2026-04-23T20:33:57.544974+08:00"},{"id":826,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-130","gmt_create":"2026-04-23T20:33:57.545482+08:00","gmt_modified":"2026-04-23T20:33:57.545482+08:00"},{"id":827,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-130","gmt_create":"2026-04-23T20:33:57.545785+08:00","gmt_modified":"2026-04-23T20:33:57.545785+08:00"},{"id":828,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-429","gmt_create":"2026-04-23T20:33:57.546196+08:00","gmt_modified":"2026-04-23T20:33:57.546196+08:00"},{"id":829,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-429","gmt_create":"2026-04-23T20:33:57.546517+08:00","gmt_modified":"2026-04-23T20:33:57.546517+08:00"},{"id":830,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:33:57.547004+08:00","gmt_modified":"2026-04-23T20:33:57.547005+08:00"},{"id":831,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-23T20:33:57.5475+08:00","gmt_modified":"2026-04-23T20:33:57.5475+08:00"},{"id":832,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:33:57.548046+08:00","gmt_modified":"2026-04-23T20:33:57.548046+08:00"},{"id":833,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"39a3b2d9301fa4eff7bef0fda3352790","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#1-206","gmt_create":"2026-04-23T20:33:57.548538+08:00","gmt_modified":"2026-04-23T20:33:57.548538+08:00"},{"id":834,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"39a3b2d9301fa4eff7bef0fda3352790","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-206","gmt_create":"2026-04-23T20:33:57.548868+08:00","gmt_modified":"2026-04-23T20:33:57.548868+08:00"},{"id":835,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fbcfae3b1238b3da5329ebafe4294861","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#1-205","gmt_create":"2026-04-23T20:33:57.549268+08:00","gmt_modified":"2026-04-23T20:33:57.549268+08:00"},{"id":836,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"fbcfae3b1238b3da5329ebafe4294861","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-205","gmt_create":"2026-04-23T20:33:57.549553+08:00","gmt_modified":"2026-04-23T20:33:57.549553+08:00"},{"id":837,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:57.550006+08:00","gmt_modified":"2026-04-23T20:33:57.550006+08:00"},{"id":838,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c4273407c88f470df7daf6a8ad5ce969","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-109","gmt_create":"2026-04-23T20:33:57.550496+08:00","gmt_modified":"2026-04-23T20:33:57.550496+08:00"},{"id":839,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c4273407c88f470df7daf6a8ad5ce969","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-109","gmt_create":"2026-04-23T20:33:57.551777+08:00","gmt_modified":"2026-04-23T20:33:57.551777+08:00"},{"id":840,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"35774e0a09ac5459c868914d7182ca95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#19-55","gmt_create":"2026-04-23T20:33:57.552775+08:00","gmt_modified":"2026-04-23T20:33:57.552775+08:00"},{"id":841,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"35774e0a09ac5459c868914d7182ca95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-55","gmt_create":"2026-04-23T20:33:57.553082+08:00","gmt_modified":"2026-04-23T20:33:57.553082+08:00"},{"id":842,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-04-23T20:33:57.553571+08:00","gmt_modified":"2026-04-23T20:33:57.553571+08:00"},{"id":843,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f639b566c26dfd18b24e3dfd2e9853ac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-52","gmt_create":"2026-04-23T20:33:57.554164+08:00","gmt_modified":"2026-04-23T20:33:57.554164+08:00"},{"id":844,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"f639b566c26dfd18b24e3dfd2e9853ac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-52","gmt_create":"2026-04-23T20:33:57.554458+08:00","gmt_modified":"2026-04-23T20:33:57.554458+08:00"},{"id":845,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:33:57.55511+08:00","gmt_modified":"2026-04-23T20:33:57.55511+08:00"},{"id":846,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:33:57.557064+08:00","gmt_modified":"2026-04-23T20:33:57.557064+08:00"},{"id":847,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:33:57.558255+08:00","gmt_modified":"2026-04-23T20:33:57.558255+08:00"},{"id":848,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-23T20:33:57.558894+08:00","gmt_modified":"2026-04-23T20:33:57.558894+08:00"},{"id":849,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T20:33:57.560321+08:00","gmt_modified":"2026-04-23T20:33:57.560321+08:00"},{"id":850,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b46654006178160f12897e2c5baac8fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-429","gmt_create":"2026-04-23T20:33:57.561417+08:00","gmt_modified":"2026-04-23T20:33:57.561417+08:00"},{"id":851,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"b46654006178160f12897e2c5baac8fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-429","gmt_create":"2026-04-23T20:33:57.561724+08:00","gmt_modified":"2026-04-23T20:33:57.561724+08:00"},{"id":852,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T20:33:57.562679+08:00","gmt_modified":"2026-04-23T20:33:57.562679+08:00"},{"id":853,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T20:33:57.563303+08:00","gmt_modified":"2026-04-23T20:33:57.563303+08:00"},{"id":854,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:33:57.563842+08:00","gmt_modified":"2026-04-23T20:33:57.563842+08:00"},{"id":855,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"82265d393c20d0af96beec6b9c657c27","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#28-41","gmt_create":"2026-04-23T20:33:57.564486+08:00","gmt_modified":"2026-04-23T20:33:57.564486+08:00"},{"id":856,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"82265d393c20d0af96beec6b9c657c27","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-41","gmt_create":"2026-04-23T20:33:57.564788+08:00","gmt_modified":"2026-04-23T20:33:57.564788+08:00"},{"id":857,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-109","gmt_create":"2026-04-23T20:33:57.565285+08:00","gmt_modified":"2026-04-23T20:33:57.565285+08:00"},{"id":858,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-23T20:33:57.565809+08:00","gmt_modified":"2026-04-23T20:33:57.565809+08:00"},{"id":859,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"93e5c95b1691bb81a36bf9a0ac889030","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-261","gmt_create":"2026-04-23T20:33:57.566399+08:00","gmt_modified":"2026-04-23T20:33:57.566399+08:00"},{"id":860,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"93e5c95b1691bb81a36bf9a0ac889030","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-261","gmt_create":"2026-04-23T20:33:57.578474+08:00","gmt_modified":"2026-04-23T20:33:57.578474+08:00"},{"id":861,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:33:57.580464+08:00","gmt_modified":"2026-04-23T20:33:57.580464+08:00"},{"id":862,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T20:33:57.581421+08:00","gmt_modified":"2026-04-23T20:33:57.581422+08:00"},{"id":863,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-48","gmt_create":"2026-04-23T20:33:57.58279+08:00","gmt_modified":"2026-04-23T20:33:57.58279+08:00"},{"id":864,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-48","gmt_create":"2026-04-23T20:33:57.583676+08:00","gmt_modified":"2026-04-23T20:33:57.583676+08:00"},{"id":865,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"374200f0bf946f0399351756977d0495","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#176-234","gmt_create":"2026-04-23T20:33:57.588601+08:00","gmt_modified":"2026-04-23T20:33:57.588601+08:00"},{"id":866,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"374200f0bf946f0399351756977d0495","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 176-234","gmt_create":"2026-04-23T20:33:57.589609+08:00","gmt_modified":"2026-04-23T20:33:57.589609+08:00"},{"id":867,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#24-32","gmt_create":"2026-04-23T20:33:57.590732+08:00","gmt_modified":"2026-04-23T20:33:57.590732+08:00"},{"id":868,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#18-33","gmt_create":"2026-04-23T20:33:57.592508+08:00","gmt_modified":"2026-04-23T20:33:57.592508+08:00"},{"id":869,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9a8d9100a6bc34ebae9ee065def7e88a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#44-72","gmt_create":"2026-04-23T20:33:57.593647+08:00","gmt_modified":"2026-04-23T20:33:57.593647+08:00"},{"id":870,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"9a8d9100a6bc34ebae9ee065def7e88a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-72","gmt_create":"2026-04-23T20:33:57.594757+08:00","gmt_modified":"2026-04-23T20:33:57.594757+08:00"},{"id":871,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"93c23bcc3456826af17e26a6d4c32116","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#6-9","gmt_create":"2026-04-23T20:33:57.595474+08:00","gmt_modified":"2026-04-23T20:33:57.595474+08:00"},{"id":872,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"93c23bcc3456826af17e26a6d4c32116","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-9","gmt_create":"2026-04-23T20:33:57.596276+08:00","gmt_modified":"2026-04-23T20:33:57.596276+08:00"},{"id":873,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c17eeb8726297096cd5542283f11494f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#17-109","gmt_create":"2026-04-23T20:33:57.597516+08:00","gmt_modified":"2026-04-23T20:33:57.597516+08:00"},{"id":874,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c17eeb8726297096cd5542283f11494f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-109","gmt_create":"2026-04-23T20:33:57.598386+08:00","gmt_modified":"2026-04-23T20:33:57.598386+08:00"},{"id":875,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"08fec4718be6991260c00ca532f9173a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#22-55","gmt_create":"2026-04-23T20:33:57.599188+08:00","gmt_modified":"2026-04-23T20:33:57.599188+08:00"},{"id":876,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"08fec4718be6991260c00ca532f9173a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-55","gmt_create":"2026-04-23T20:33:57.600043+08:00","gmt_modified":"2026-04-23T20:33:57.600043+08:00"},{"id":877,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"08007199eea846dd14f15f7dc70419e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#48-52","gmt_create":"2026-04-23T20:33:57.600852+08:00","gmt_modified":"2026-04-23T20:33:57.600852+08:00"},{"id":878,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"08007199eea846dd14f15f7dc70419e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-52","gmt_create":"2026-04-23T20:33:57.601489+08:00","gmt_modified":"2026-04-23T20:33:57.601489+08:00"},{"id":879,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"4caff756fd4da029bd64cd16e7ef5960","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#32-39","gmt_create":"2026-04-23T20:33:57.602322+08:00","gmt_modified":"2026-04-23T20:33:57.602323+08:00"},{"id":880,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"4caff756fd4da029bd64cd16e7ef5960","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-39","gmt_create":"2026-04-23T20:33:57.602918+08:00","gmt_modified":"2026-04-23T20:33:57.602918+08:00"},{"id":881,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b0220895f66f1273966ad5b2c3266952","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#49-53","gmt_create":"2026-04-23T20:33:57.603881+08:00","gmt_modified":"2026-04-23T20:33:57.603881+08:00"},{"id":882,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"b0220895f66f1273966ad5b2c3266952","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-53","gmt_create":"2026-04-23T20:33:57.604555+08:00","gmt_modified":"2026-04-23T20:33:57.604555+08:00"},{"id":883,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"44f88f9664fdf6e84ffb7e0675a86a28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#64-69","gmt_create":"2026-04-23T20:33:57.605262+08:00","gmt_modified":"2026-04-23T20:33:57.605262+08:00"},{"id":884,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"44f88f9664fdf6e84ffb7e0675a86a28","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 64-69","gmt_create":"2026-04-23T20:33:57.606324+08:00","gmt_modified":"2026-04-23T20:33:57.606324+08:00"},{"id":885,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"91f280f51389bd1cf711dcf33a4da681","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#79-84","gmt_create":"2026-04-23T20:33:57.607055+08:00","gmt_modified":"2026-04-23T20:33:57.607055+08:00"},{"id":886,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"91f280f51389bd1cf711dcf33a4da681","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-84","gmt_create":"2026-04-23T20:33:57.608388+08:00","gmt_modified":"2026-04-23T20:33:57.608388+08:00"},{"id":887,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ab50466a57c77659d7b469d3a8a04ddb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#96-103","gmt_create":"2026-04-23T20:33:57.609206+08:00","gmt_modified":"2026-04-23T20:33:57.609206+08:00"},{"id":888,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"ab50466a57c77659d7b469d3a8a04ddb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 96-103","gmt_create":"2026-04-23T20:33:57.609975+08:00","gmt_modified":"2026-04-23T20:33:57.609975+08:00"},{"id":889,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#65-71","gmt_create":"2026-04-23T20:33:57.61104+08:00","gmt_modified":"2026-04-23T20:33:57.611041+08:00"},{"id":890,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-71","gmt_create":"2026-04-23T20:33:57.611833+08:00","gmt_modified":"2026-04-23T20:33:57.611833+08:00"},{"id":891,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"82386bc7ca57d9ccc94b656e52bc89f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-14","gmt_create":"2026-04-23T20:33:57.612865+08:00","gmt_modified":"2026-04-23T20:33:57.612865+08:00"},{"id":892,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"82386bc7ca57d9ccc94b656e52bc89f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-04-23T20:33:57.613537+08:00","gmt_modified":"2026-04-23T20:33:57.613537+08:00"},{"id":893,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"7ab79ab21d7d6e4dbcb224572516f6f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-19","gmt_create":"2026-04-23T20:33:57.613967+08:00","gmt_modified":"2026-04-23T20:33:57.613968+08:00"},{"id":894,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"7ab79ab21d7d6e4dbcb224572516f6f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-19","gmt_create":"2026-04-23T20:33:57.61426+08:00","gmt_modified":"2026-04-23T20:33:57.61426+08:00"},{"id":895,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"8433204d7a82a1f480e57df9ceee5581","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-10","gmt_create":"2026-04-23T20:33:57.614658+08:00","gmt_modified":"2026-04-23T20:33:57.614658+08:00"},{"id":896,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"8433204d7a82a1f480e57df9ceee5581","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-23T20:33:57.614988+08:00","gmt_modified":"2026-04-23T20:33:57.614988+08:00"},{"id":897,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"3957ee6f15a01b7b541490438ef18684","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-17","gmt_create":"2026-04-23T20:33:57.615388+08:00","gmt_modified":"2026-04-23T20:33:57.615388+08:00"},{"id":898,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"3957ee6f15a01b7b541490438ef18684","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-17","gmt_create":"2026-04-23T20:33:57.615908+08:00","gmt_modified":"2026-04-23T20:33:57.615908+08:00"},{"id":899,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-157","gmt_create":"2026-04-23T20:33:57.61673+08:00","gmt_modified":"2026-04-23T20:33:57.61673+08:00"},{"id":900,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fcae8d1d281ad7186999cc4ca8e43db7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-39","gmt_create":"2026-04-23T20:33:57.617716+08:00","gmt_modified":"2026-04-23T20:33:57.617716+08:00"},{"id":901,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"fcae8d1d281ad7186999cc4ca8e43db7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-39","gmt_create":"2026-04-23T20:33:57.618148+08:00","gmt_modified":"2026-04-23T20:33:57.618148+08:00"},{"id":902,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ee12a84ac6334b13e20132181454488b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#13-19","gmt_create":"2026-04-23T20:33:57.6192+08:00","gmt_modified":"2026-04-23T20:33:57.6192+08:00"},{"id":903,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"ee12a84ac6334b13e20132181454488b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-19","gmt_create":"2026-04-23T20:33:57.619587+08:00","gmt_modified":"2026-04-23T20:33:57.619587+08:00"},{"id":904,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"897e047b94772e5a0ff57cf773a7f965","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#17-32","gmt_create":"2026-04-23T20:33:57.620024+08:00","gmt_modified":"2026-04-23T20:33:57.620024+08:00"},{"id":905,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"897e047b94772e5a0ff57cf773a7f965","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-32","gmt_create":"2026-04-23T20:33:57.620315+08:00","gmt_modified":"2026-04-23T20:33:57.620315+08:00"},{"id":906,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"53e8ec81b4d2dbb13c831048e5897036","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#17-32","gmt_create":"2026-04-23T20:33:57.620909+08:00","gmt_modified":"2026-04-23T20:33:57.620909+08:00"},{"id":907,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"53e8ec81b4d2dbb13c831048e5897036","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-32","gmt_create":"2026-04-23T20:33:57.621267+08:00","gmt_modified":"2026-04-23T20:33:57.621267+08:00"},{"id":908,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:57.621687+08:00","gmt_modified":"2026-04-23T20:33:57.621687+08:00"},{"id":909,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-32","gmt_create":"2026-04-23T20:33:57.62216+08:00","gmt_modified":"2026-04-23T20:33:57.62216+08:00"},{"id":910,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-32","gmt_create":"2026-04-23T20:33:57.623241+08:00","gmt_modified":"2026-04-23T20:33:57.623241+08:00"},{"id":911,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T20:33:57.627555+08:00","gmt_modified":"2026-04-23T20:33:57.627555+08:00"},{"id":912,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T20:33:57.62809+08:00","gmt_modified":"2026-04-23T20:33:57.62809+08:00"},{"id":913,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fd3145047b9c813cc8e64b9322e531f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-327","gmt_create":"2026-04-23T20:33:57.62931+08:00","gmt_modified":"2026-04-23T20:33:57.62931+08:00"},{"id":914,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"fd3145047b9c813cc8e64b9322e531f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-327","gmt_create":"2026-04-23T20:33:57.629745+08:00","gmt_modified":"2026-04-23T20:33:57.629745+08:00"},{"id":915,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b09a0f415030d91b25e6cabd8a0a93fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#176-289","gmt_create":"2026-04-23T20:33:57.630458+08:00","gmt_modified":"2026-04-23T20:33:57.630458+08:00"},{"id":916,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"b09a0f415030d91b25e6cabd8a0a93fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 176-289","gmt_create":"2026-04-23T20:33:57.630748+08:00","gmt_modified":"2026-04-23T20:33:57.630748+08:00"},{"id":917,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e2168959b26c386940370b5f1bf48d7d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#194-204","gmt_create":"2026-04-23T20:33:57.631184+08:00","gmt_modified":"2026-04-23T20:33:57.631184+08:00"},{"id":918,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"e2168959b26c386940370b5f1bf48d7d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 194-204","gmt_create":"2026-04-23T20:33:57.63147+08:00","gmt_modified":"2026-04-23T20:33:57.63147+08:00"},{"id":919,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:35:18.634061+08:00","gmt_modified":"2026-04-23T20:35:18.634062+08:00"},{"id":920,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:35:18.634886+08:00","gmt_modified":"2026-04-23T20:35:18.634886+08:00"},{"id":921,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:35:18.635377+08:00","gmt_modified":"2026-04-23T20:35:18.635377+08:00"},{"id":922,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4a56ef5fca60bc63480b457cab3832f0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/__init__.py","gmt_create":"2026-04-23T20:35:18.63595+08:00","gmt_modified":"2026-04-23T20:35:18.63595+08:00"},{"id":923,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:35:18.636363+08:00","gmt_modified":"2026-04-23T20:35:18.636363+08:00"},{"id":924,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:35:18.636753+08:00","gmt_modified":"2026-04-23T20:35:18.636753+08:00"},{"id":925,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"36dd0ad3ee6bc75a480ad8a62268e80e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/models/query.py","gmt_create":"2026-04-23T20:35:18.6372+08:00","gmt_modified":"2026-04-23T20:35:18.6372+08:00"},{"id":926,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:35:18.637558+08:00","gmt_modified":"2026-04-23T20:35:18.637558+08:00"},{"id":927,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:35:18.637924+08:00","gmt_modified":"2026-04-23T20:35:18.637924+08:00"},{"id":928,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:35:18.638407+08:00","gmt_modified":"2026-04-23T20:35:18.638407+08:00"},{"id":929,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:35:18.638942+08:00","gmt_modified":"2026-04-23T20:35:18.638942+08:00"},{"id":930,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:35:18.641162+08:00","gmt_modified":"2026-04-23T20:35:18.641162+08:00"},{"id":931,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:35:18.642251+08:00","gmt_modified":"2026-04-23T20:35:18.642251+08:00"},{"id":932,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:35:18.642925+08:00","gmt_modified":"2026-04-23T20:35:18.642925+08:00"},{"id":933,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T20:35:18.643414+08:00","gmt_modified":"2026-04-23T20:35:18.643415+08:00"},{"id":934,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:35:18.643912+08:00","gmt_modified":"2026-04-23T20:35:18.643912+08:00"},{"id":935,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"129573d2bbcde48697ed0e75dea12396","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-40","gmt_create":"2026-04-23T20:35:18.645078+08:00","gmt_modified":"2026-04-23T20:35:18.645078+08:00"},{"id":936,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"129573d2bbcde48697ed0e75dea12396","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-40","gmt_create":"2026-04-23T20:35:18.646964+08:00","gmt_modified":"2026-04-23T20:35:18.646965+08:00"},{"id":937,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"cf18c97a9be6c78aa43cc229ed3dad20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#164-173","gmt_create":"2026-04-23T20:35:18.647598+08:00","gmt_modified":"2026-04-23T20:35:18.647598+08:00"},{"id":938,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"cf18c97a9be6c78aa43cc229ed3dad20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 164-173","gmt_create":"2026-04-23T20:35:18.647972+08:00","gmt_modified":"2026-04-23T20:35:18.647972+08:00"},{"id":939,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"3c7ca5d582dca31c2530b1ce9c058e95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#10-37","gmt_create":"2026-04-23T20:35:18.648459+08:00","gmt_modified":"2026-04-23T20:35:18.64846+08:00"},{"id":940,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"3c7ca5d582dca31c2530b1ce9c058e95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-37","gmt_create":"2026-04-23T20:35:18.648785+08:00","gmt_modified":"2026-04-23T20:35:18.648785+08:00"},{"id":941,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:35:18.649264+08:00","gmt_modified":"2026-04-23T20:35:18.649264+08:00"},{"id":942,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:35:18.650358+08:00","gmt_modified":"2026-04-23T20:35:18.650358+08:00"},{"id":943,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:35:18.650954+08:00","gmt_modified":"2026-04-23T20:35:18.650954+08:00"},{"id":944,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:35:18.652232+08:00","gmt_modified":"2026-04-23T20:35:18.652232+08:00"},{"id":945,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:35:18.653511+08:00","gmt_modified":"2026-04-23T20:35:18.653511+08:00"},{"id":946,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"27047f868643e5457d4f242b4298a9f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-23","gmt_create":"2026-04-23T20:35:18.654994+08:00","gmt_modified":"2026-04-23T20:35:18.654994+08:00"},{"id":947,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"27047f868643e5457d4f242b4298a9f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T20:35:18.6556+08:00","gmt_modified":"2026-04-23T20:35:18.6556+08:00"},{"id":948,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:35:18.657485+08:00","gmt_modified":"2026-04-23T20:35:18.657486+08:00"},{"id":949,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"1526e4e02133a48eac04befb74ec5bd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-173","gmt_create":"2026-04-23T20:35:18.65887+08:00","gmt_modified":"2026-04-23T20:35:18.65887+08:00"},{"id":950,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1526e4e02133a48eac04befb74ec5bd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-173","gmt_create":"2026-04-23T20:35:18.659265+08:00","gmt_modified":"2026-04-23T20:35:18.659265+08:00"},{"id":951,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#26-39","gmt_create":"2026-04-23T20:35:18.661103+08:00","gmt_modified":"2026-04-23T20:35:18.661103+08:00"},{"id":952,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-39","gmt_create":"2026-04-23T20:35:18.661433+08:00","gmt_modified":"2026-04-23T20:35:18.661433+08:00"},{"id":953,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-04-23T20:35:18.661922+08:00","gmt_modified":"2026-04-23T20:35:18.661922+08:00"},{"id":954,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-23T20:35:18.662781+08:00","gmt_modified":"2026-04-23T20:35:18.662781+08:00"},{"id":955,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-234","gmt_create":"2026-04-23T20:35:18.680675+08:00","gmt_modified":"2026-04-23T20:35:18.680675+08:00"},{"id":956,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:35:18.68314+08:00","gmt_modified":"2026-04-23T20:35:18.68314+08:00"},{"id":957,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:35:18.685341+08:00","gmt_modified":"2026-04-23T20:35:18.685341+08:00"},{"id":958,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-33","gmt_create":"2026-04-23T20:35:18.686894+08:00","gmt_modified":"2026-04-23T20:35:18.686894+08:00"},{"id":959,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"2a971cb83924013902324eceeab22559","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-29","gmt_create":"2026-04-23T20:35:18.689849+08:00","gmt_modified":"2026-04-23T20:35:18.689849+08:00"},{"id":960,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"2a971cb83924013902324eceeab22559","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-29","gmt_create":"2026-04-23T20:35:18.69154+08:00","gmt_modified":"2026-04-23T20:35:18.69154+08:00"},{"id":961,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"99326fedad9275392719105b5b6782d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#31-33","gmt_create":"2026-04-23T20:35:18.692776+08:00","gmt_modified":"2026-04-23T20:35:18.692776+08:00"},{"id":962,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"99326fedad9275392719105b5b6782d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-33","gmt_create":"2026-04-23T20:35:18.693945+08:00","gmt_modified":"2026-04-23T20:35:18.693945+08:00"},{"id":963,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-144","gmt_create":"2026-04-23T20:35:18.695323+08:00","gmt_modified":"2026-04-23T20:35:18.695324+08:00"},{"id":964,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5e5dacc623918c0f1eba234154c99291","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#16-76","gmt_create":"2026-04-23T20:35:18.696341+08:00","gmt_modified":"2026-04-23T20:35:18.696341+08:00"},{"id":965,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"5e5dacc623918c0f1eba234154c99291","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-76","gmt_create":"2026-04-23T20:35:18.697266+08:00","gmt_modified":"2026-04-23T20:35:18.697267+08:00"},{"id":966,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5be7e6cf82d6359efddaf131aaf92615","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#323-330","gmt_create":"2026-04-23T20:35:18.701473+08:00","gmt_modified":"2026-04-23T20:35:18.701473+08:00"},{"id":967,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"5be7e6cf82d6359efddaf131aaf92615","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 323-330","gmt_create":"2026-04-23T20:35:18.7021+08:00","gmt_modified":"2026-04-23T20:35:18.7021+08:00"},{"id":968,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#86-90","gmt_create":"2026-04-23T20:35:18.703871+08:00","gmt_modified":"2026-04-23T20:35:18.703871+08:00"},{"id":969,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-90","gmt_create":"2026-04-23T20:35:18.709231+08:00","gmt_modified":"2026-04-23T20:35:18.709231+08:00"},{"id":970,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T20:35:18.712574+08:00","gmt_modified":"2026-04-23T20:35:18.712574+08:00"},{"id":971,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-77","gmt_create":"2026-04-23T20:35:18.713529+08:00","gmt_modified":"2026-04-23T20:35:18.713529+08:00"},{"id":972,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T20:35:18.714412+08:00","gmt_modified":"2026-04-23T20:35:18.714412+08:00"},{"id":973,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"d780e807ee751f39f331a658b47c4ed3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#24-269","gmt_create":"2026-04-23T20:35:18.715261+08:00","gmt_modified":"2026-04-23T20:35:18.715261+08:00"},{"id":974,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"d780e807ee751f39f331a658b47c4ed3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-269","gmt_create":"2026-04-23T20:35:18.716135+08:00","gmt_modified":"2026-04-23T20:35:18.716135+08:00"},{"id":975,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8eea43550951387ac740b5e3e64c7691","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#94-96","gmt_create":"2026-04-23T20:35:18.720519+08:00","gmt_modified":"2026-04-23T20:35:18.720519+08:00"},{"id":976,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"8eea43550951387ac740b5e3e64c7691","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 94-96","gmt_create":"2026-04-23T20:35:18.72132+08:00","gmt_modified":"2026-04-23T20:35:18.72132+08:00"},{"id":977,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#50-54","gmt_create":"2026-04-23T20:35:18.72244+08:00","gmt_modified":"2026-04-23T20:35:18.72244+08:00"},{"id":978,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#37-41","gmt_create":"2026-04-23T20:35:18.725156+08:00","gmt_modified":"2026-04-23T20:35:18.725157+08:00"},{"id":979,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:35:18.727146+08:00","gmt_modified":"2026-04-23T20:35:18.727146+08:00"},{"id":980,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"37769b7e6b5588be0065681dedf514ed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#140-144","gmt_create":"2026-04-23T20:35:18.728033+08:00","gmt_modified":"2026-04-23T20:35:18.728033+08:00"},{"id":981,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"37769b7e6b5588be0065681dedf514ed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 140-144","gmt_create":"2026-04-23T20:35:18.728855+08:00","gmt_modified":"2026-04-23T20:35:18.728855+08:00"},{"id":982,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"518d184988b97ebc7ef0c0bf5c10f42c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#24-29","gmt_create":"2026-04-23T20:35:18.72968+08:00","gmt_modified":"2026-04-23T20:35:18.72968+08:00"},{"id":983,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"518d184988b97ebc7ef0c0bf5c10f42c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-29","gmt_create":"2026-04-23T20:35:18.730545+08:00","gmt_modified":"2026-04-23T20:35:18.730546+08:00"},{"id":984,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"818504ee2e17d2f9cc8fe115ca321138","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#34-38","gmt_create":"2026-04-23T20:35:18.73162+08:00","gmt_modified":"2026-04-23T20:35:18.73162+08:00"},{"id":985,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"818504ee2e17d2f9cc8fe115ca321138","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-38","gmt_create":"2026-04-23T20:35:18.732614+08:00","gmt_modified":"2026-04-23T20:35:18.732614+08:00"},{"id":986,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#67-71","gmt_create":"2026-04-23T20:35:18.733467+08:00","gmt_modified":"2026-04-23T20:35:18.733467+08:00"},{"id":987,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-56","gmt_create":"2026-04-23T20:35:18.735579+08:00","gmt_modified":"2026-04-23T20:35:18.735579+08:00"},{"id":988,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-56","gmt_create":"2026-04-23T20:35:18.73663+08:00","gmt_modified":"2026-04-23T20:35:18.73663+08:00"},{"id":1012,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"d4f99d3dd9fe489c354edf5fe2f8803d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-44","gmt_create":"2026-04-23T20:35:45.713712+08:00","gmt_modified":"2026-04-23T20:35:45.713713+08:00"},{"id":1015,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"86e37040be1aeb400fab9b529f5404c8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:35:45.722046+08:00","gmt_modified":"2026-04-23T20:35:45.722047+08:00"},{"id":1017,"source_id":"a680d4819f5da57fe9fa0e6bc708f380","target_id":"211463f5b49610f09594c40c0a235943","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-89","gmt_create":"2026-04-23T20:35:45.736063+08:00","gmt_modified":"2026-04-23T20:35:45.736064+08:00"},{"id":1019,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-71","gmt_create":"2026-04-23T20:35:45.743112+08:00","gmt_modified":"2026-04-23T20:35:45.743112+08:00"},{"id":1022,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"98cc82f62b83678f06a33cf9231ecdf8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-128","gmt_create":"2026-04-23T20:35:45.771158+08:00","gmt_modified":"2026-04-23T20:35:45.771158+08:00"},{"id":1024,"source_id":"f6e6948dd0cdd3894bd9928b21feb979","target_id":"e1aabd52989e47806fb997157381e1cf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:35:45.782446+08:00","gmt_modified":"2026-04-23T20:35:45.782446+08:00"},{"id":1028,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"ac77e4875817616194b7b5997d4fb1ae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-94","gmt_create":"2026-04-23T20:35:45.808076+08:00","gmt_modified":"2026-04-23T20:35:45.808076+08:00"},{"id":1030,"source_id":"f6e6948dd0cdd3894bd9928b21feb979","target_id":"0e57efd98dacc85da21f995980371ee4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-37","gmt_create":"2026-04-23T20:35:45.81891+08:00","gmt_modified":"2026-04-23T20:35:45.81891+08:00"},{"id":1033,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"717eb27184726e4f78d694984d29420c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-44","gmt_create":"2026-04-23T20:35:45.831123+08:00","gmt_modified":"2026-04-23T20:35:45.831123+08:00"},{"id":1037,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"bfdf3479f244dc6794628d9df10ab6d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-48","gmt_create":"2026-04-23T20:35:45.842187+08:00","gmt_modified":"2026-04-23T20:35:45.842187+08:00"},{"id":1039,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"f5f9f0d96263ae84631c7a8d7e9b3648","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-44","gmt_create":"2026-04-23T20:35:45.84404+08:00","gmt_modified":"2026-04-23T20:35:45.84404+08:00"},{"id":1041,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"818d1354dc0665798f3d91a2ca5153d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-34","gmt_create":"2026-04-23T20:35:45.845935+08:00","gmt_modified":"2026-04-23T20:35:45.845935+08:00"},{"id":1043,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"24aade4c34609a8ab28e4643a3692201","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-36","gmt_create":"2026-04-23T20:35:45.853262+08:00","gmt_modified":"2026-04-23T20:35:45.853263+08:00"},{"id":1045,"source_id":"a680d4819f5da57fe9fa0e6bc708f380","target_id":"d34337b9ff77246979252d2fd8fb8018","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-88","gmt_create":"2026-04-23T20:35:45.866334+08:00","gmt_modified":"2026-04-23T20:35:45.866335+08:00"},{"id":1048,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"eb63042f04a22f9a67bd498df1684d20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-111","gmt_create":"2026-04-23T20:35:45.883763+08:00","gmt_modified":"2026-04-23T20:35:45.883763+08:00"},{"id":1051,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"c651c7ad6747a92ee96eabb2eb82afdd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-18","gmt_create":"2026-04-23T20:35:45.891674+08:00","gmt_modified":"2026-04-23T20:35:45.891674+08:00"},{"id":1053,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dd01eee487298a28e950f6345196f1d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-79","gmt_create":"2026-04-23T20:35:45.895814+08:00","gmt_modified":"2026-04-23T20:35:45.895814+08:00"},{"id":1055,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"7dae7237f11c5100bf7889c105193cf6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-32","gmt_create":"2026-04-23T20:35:45.901349+08:00","gmt_modified":"2026-04-23T20:35:45.901349+08:00"},{"id":1057,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"cc64cf609f5ff218f618e0664ffa7cc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 298-308","gmt_create":"2026-04-23T20:35:45.904411+08:00","gmt_modified":"2026-04-23T20:35:45.904411+08:00"},{"id":1059,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"ce7e334595a4ce912e0d116314db9a35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 342-429","gmt_create":"2026-04-23T20:35:45.906963+08:00","gmt_modified":"2026-04-23T20:35:45.906964+08:00"},{"id":1061,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"2f46f212597e3c245b9e5dcc5dbc863d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-18","gmt_create":"2026-04-23T20:35:45.909475+08:00","gmt_modified":"2026-04-23T20:35:45.909476+08:00"},{"id":1063,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dc40f1dd3e59ee7f046019201068bea1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-22","gmt_create":"2026-04-23T20:35:45.920772+08:00","gmt_modified":"2026-04-23T20:35:45.920772+08:00"},{"id":1069,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e a1cc822d-5382-431c-8c49-cf398fb5eb3c","gmt_create":"2026-04-23T20:35:46.950364+08:00","gmt_modified":"2026-04-23T20:35:46.950364+08:00"},{"id":1070,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"37003fc0-1cf5-4264-996b-40807001875f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 37003fc0-1cf5-4264-996b-40807001875f","gmt_create":"2026-04-23T20:35:46.957122+08:00","gmt_modified":"2026-04-23T20:35:46.957122+08:00"},{"id":1071,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 2126339b-b0f5-4152-924b-cbe028cd0c39","gmt_create":"2026-04-23T20:35:46.959782+08:00","gmt_modified":"2026-04-23T20:35:46.959782+08:00"},{"id":1072,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e fab60eaf-9652-4cb5-9f9e-0525caa62d63","gmt_create":"2026-04-23T20:35:46.965729+08:00","gmt_modified":"2026-04-23T20:35:46.965729+08:00"},{"id":1073,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"00359e45-209d-4be3-8795-50dea52bdba1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 00359e45-209d-4be3-8795-50dea52bdba1","gmt_create":"2026-04-23T20:35:46.970985+08:00","gmt_modified":"2026-04-23T20:35:46.970985+08:00"},{"id":1074,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2632a6f9-774e-4a91-94da-a984bdb20758","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 2632a6f9-774e-4a91-94da-a984bdb20758","gmt_create":"2026-04-23T20:35:46.974435+08:00","gmt_modified":"2026-04-23T20:35:46.974435+08:00"},{"id":1076,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-23T21:00:59.656249+08:00","gmt_modified":"2026-04-23T21:00:59.656249+08:00"},{"id":1077,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-23T21:00:59.656613+08:00","gmt_modified":"2026-04-23T21:00:59.656613+08:00"},{"id":1078,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T21:00:59.656928+08:00","gmt_modified":"2026-04-23T21:00:59.656928+08:00"},{"id":1079,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-04-23T21:00:59.657229+08:00","gmt_modified":"2026-04-23T21:00:59.657229+08:00"},{"id":1080,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"5e414f2ef9b69e55e00ab15f85b9291a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/Dockerfile","gmt_create":"2026-04-23T21:00:59.657778+08:00","gmt_modified":"2026-04-23T21:00:59.657779+08:00"},{"id":1081,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-04-23T21:00:59.658783+08:00","gmt_modified":"2026-04-23T21:00:59.658783+08:00"},{"id":1082,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic.ini","gmt_create":"2026-04-23T21:00:59.659121+08:00","gmt_modified":"2026-04-23T21:00:59.659121+08:00"},{"id":1083,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T21:00:59.659433+08:00","gmt_modified":"2026-04-23T21:00:59.659433+08:00"},{"id":1084,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"fb8af100a06778e1fbdac4790a3ed0a9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tsconfig.json","gmt_create":"2026-04-23T21:00:59.659973+08:00","gmt_modified":"2026-04-23T21:00:59.659973+08:00"},{"id":1085,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-04-23T21:00:59.660739+08:00","gmt_modified":"2026-04-23T21:00:59.660739+08:00"},{"id":1086,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4d9b59c294a0aac5e300b3de715eb226","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/.eslintrc.json","gmt_create":"2026-04-23T21:00:59.661096+08:00","gmt_modified":"2026-04-23T21:00:59.661097+08:00"},{"id":1087,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-04-23T21:00:59.661386+08:00","gmt_modified":"2026-04-23T21:00:59.661386+08:00"},{"id":1088,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-23T21:00:59.661691+08:00","gmt_modified":"2026-04-23T21:00:59.661691+08:00"},{"id":1089,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-23T21:00:59.661989+08:00","gmt_modified":"2026-04-23T21:00:59.661989+08:00"},{"id":1090,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-23T21:00:59.662317+08:00","gmt_modified":"2026-04-23T21:00:59.662317+08:00"},{"id":1091,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"48a560c49d2b21da327c036ec2934b96","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: README.md","gmt_create":"2026-04-23T21:00:59.662608+08:00","gmt_modified":"2026-04-23T21:00:59.662608+08:00"},{"id":1092,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-04-23T21:00:59.663719+08:00","gmt_modified":"2026-04-23T21:00:59.663719+08:00"},{"id":1093,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"01a0c4b40819965823b56e9da858c024","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/Dockerfile#1-15","gmt_create":"2026-04-23T21:00:59.66424+08:00","gmt_modified":"2026-04-23T21:00:59.66424+08:00"},{"id":1094,"source_id":"5e414f2ef9b69e55e00ab15f85b9291a","target_id":"01a0c4b40819965823b56e9da858c024","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-15","gmt_create":"2026-04-23T21:00:59.664546+08:00","gmt_modified":"2026-04-23T21:00:59.664546+08:00"},{"id":1095,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"412695e5de2014514a8f62f98c573656","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#1-41","gmt_create":"2026-04-23T21:00:59.66492+08:00","gmt_modified":"2026-04-23T21:00:59.66492+08:00"},{"id":1096,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-23T21:00:59.665702+08:00","gmt_modified":"2026-04-23T21:00:59.665702+08:00"},{"id":1097,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-35","gmt_create":"2026-04-23T21:00:59.688277+08:00","gmt_modified":"2026-04-23T21:00:59.688278+08:00"},{"id":1098,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T21:00:59.689553+08:00","gmt_modified":"2026-04-23T21:00:59.689553+08:00"},{"id":1099,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-23T21:00:59.690337+08:00","gmt_modified":"2026-04-23T21:00:59.690337+08:00"},{"id":1100,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"13f6ca76349ef86ae756bb519f122bc5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#1-150","gmt_create":"2026-04-23T21:00:59.691229+08:00","gmt_modified":"2026-04-23T21:00:59.691229+08:00"},{"id":1101,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"13f6ca76349ef86ae756bb519f122bc5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-150","gmt_create":"2026-04-23T21:00:59.691641+08:00","gmt_modified":"2026-04-23T21:00:59.691641+08:00"},{"id":1102,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"74abd6612105c29b67178fa9dbd04b61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tsconfig.json#1-27","gmt_create":"2026-04-23T21:00:59.696048+08:00","gmt_modified":"2026-04-23T21:00:59.696048+08:00"},{"id":1103,"source_id":"fb8af100a06778e1fbdac4790a3ed0a9","target_id":"74abd6612105c29b67178fa9dbd04b61","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-27","gmt_create":"2026-04-23T21:00:59.696535+08:00","gmt_modified":"2026-04-23T21:00:59.696535+08:00"},{"id":1104,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"5bdaabf085a7c3eb6e87c5ad7479e25d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/.eslintrc.json#1-4","gmt_create":"2026-04-23T21:00:59.697248+08:00","gmt_modified":"2026-04-23T21:00:59.697248+08:00"},{"id":1105,"source_id":"4d9b59c294a0aac5e300b3de715eb226","target_id":"5bdaabf085a7c3eb6e87c5ad7479e25d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-4","gmt_create":"2026-04-23T21:00:59.697778+08:00","gmt_modified":"2026-04-23T21:00:59.697778+08:00"},{"id":1106,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-57","gmt_create":"2026-04-23T21:00:59.69854+08:00","gmt_modified":"2026-04-23T21:00:59.69854+08:00"},{"id":1107,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9482f4f6279a4f636b77e69b8273b996","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#86-114","gmt_create":"2026-04-23T21:00:59.700127+08:00","gmt_modified":"2026-04-23T21:00:59.700127+08:00"},{"id":1108,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"9482f4f6279a4f636b77e69b8273b996","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-114","gmt_create":"2026-04-23T21:00:59.700939+08:00","gmt_modified":"2026-04-23T21:00:59.70094+08:00"},{"id":1109,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"397b266f19a1addebdf6c32db71ae77f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-71","gmt_create":"2026-04-23T21:00:59.70244+08:00","gmt_modified":"2026-04-23T21:00:59.70244+08:00"},{"id":1110,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"397b266f19a1addebdf6c32db71ae77f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-71","gmt_create":"2026-04-23T21:00:59.703412+08:00","gmt_modified":"2026-04-23T21:00:59.703413+08:00"},{"id":1111,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"b55a164add5a8fec2ef0e489f7234829","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-47","gmt_create":"2026-04-23T21:00:59.707909+08:00","gmt_modified":"2026-04-23T21:00:59.707909+08:00"},{"id":1112,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"eb603ec2611957de67af00756f4b1efa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-13","gmt_create":"2026-04-23T21:00:59.708942+08:00","gmt_modified":"2026-04-23T21:00:59.708942+08:00"},{"id":1113,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"eb603ec2611957de67af00756f4b1efa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-13","gmt_create":"2026-04-23T21:00:59.713128+08:00","gmt_modified":"2026-04-23T21:00:59.713128+08:00"},{"id":1114,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c25b39830f3b7734da975acc7f214666","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#31-33","gmt_create":"2026-04-23T21:00:59.714181+08:00","gmt_modified":"2026-04-23T21:00:59.714181+08:00"},{"id":1115,"source_id":"e9b52adbec3c07cf021e488dd3f99ab4","target_id":"c25b39830f3b7734da975acc7f214666","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-33","gmt_create":"2026-04-23T21:00:59.71645+08:00","gmt_modified":"2026-04-23T21:00:59.71645+08:00"},{"id":1116,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4c9d362ecce8e796e6f14850def049b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#4-20","gmt_create":"2026-04-23T21:00:59.717301+08:00","gmt_modified":"2026-04-23T21:00:59.717301+08:00"},{"id":1117,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"4c9d362ecce8e796e6f14850def049b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-20","gmt_create":"2026-04-23T21:00:59.718148+08:00","gmt_modified":"2026-04-23T21:00:59.718148+08:00"},{"id":1118,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"d5827be2cfbe41c8177660ae877e93a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#22-34","gmt_create":"2026-04-23T21:00:59.719092+08:00","gmt_modified":"2026-04-23T21:00:59.719092+08:00"},{"id":1119,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"d5827be2cfbe41c8177660ae877e93a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-34","gmt_create":"2026-04-23T21:00:59.719965+08:00","gmt_modified":"2026-04-23T21:00:59.719965+08:00"},{"id":1120,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"03a65cdcfc173217d12ad8a417f8f033","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-21","gmt_create":"2026-04-23T21:00:59.720372+08:00","gmt_modified":"2026-04-23T21:00:59.720372+08:00"},{"id":1121,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"03a65cdcfc173217d12ad8a417f8f033","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-21","gmt_create":"2026-04-23T21:00:59.721352+08:00","gmt_modified":"2026-04-23T21:00:59.721353+08:00"},{"id":1122,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-04-23T21:00:59.722016+08:00","gmt_modified":"2026-04-23T21:00:59.722016+08:00"},{"id":1123,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"3365fa8db33d43bab1d0a614e8af3a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#45-47","gmt_create":"2026-04-23T21:00:59.722511+08:00","gmt_modified":"2026-04-23T21:00:59.722511+08:00"},{"id":1124,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"3365fa8db33d43bab1d0a614e8af3a70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-47","gmt_create":"2026-04-23T21:00:59.724292+08:00","gmt_modified":"2026-04-23T21:00:59.724292+08:00"},{"id":1125,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#7-34","gmt_create":"2026-04-23T21:00:59.725223+08:00","gmt_modified":"2026-04-23T21:00:59.725223+08:00"},{"id":1126,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-23T21:00:59.725972+08:00","gmt_modified":"2026-04-23T21:00:59.725972+08:00"},{"id":1127,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-04-23T21:00:59.727037+08:00","gmt_modified":"2026-04-23T21:00:59.727038+08:00"},{"id":1128,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#1-34","gmt_create":"2026-04-23T21:00:59.728108+08:00","gmt_modified":"2026-04-23T21:00:59.728108+08:00"},{"id":1129,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-34","gmt_create":"2026-04-23T21:00:59.728891+08:00","gmt_modified":"2026-04-23T21:00:59.728891+08:00"},{"id":1130,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-04-23T21:00:59.729618+08:00","gmt_modified":"2026-04-23T21:00:59.729618+08:00"},{"id":1131,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"a698e13bfada239280fc9354ff9e2331","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-8","gmt_create":"2026-04-23T21:00:59.731437+08:00","gmt_modified":"2026-04-23T21:00:59.731438+08:00"},{"id":1132,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"a698e13bfada239280fc9354ff9e2331","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-8","gmt_create":"2026-04-23T21:00:59.731927+08:00","gmt_modified":"2026-04-23T21:00:59.731927+08:00"},{"id":1133,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"37bbab6e4f16db7eac6eee9d05e80e46","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: README.md#1-3","gmt_create":"2026-04-23T21:00:59.737212+08:00","gmt_modified":"2026-04-23T21:00:59.737212+08:00"},{"id":1134,"source_id":"48a560c49d2b21da327c036ec2934b96","target_id":"37bbab6e4f16db7eac6eee9d05e80e46","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-3","gmt_create":"2026-04-23T21:00:59.737807+08:00","gmt_modified":"2026-04-23T21:00:59.737807+08:00"},{"id":1135,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"63ecbf5e72a0354028b84eb531a58977","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#11-38","gmt_create":"2026-04-23T21:00:59.738706+08:00","gmt_modified":"2026-04-23T21:00:59.738706+08:00"},{"id":1136,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"63ecbf5e72a0354028b84eb531a58977","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-38","gmt_create":"2026-04-23T21:00:59.738981+08:00","gmt_modified":"2026-04-23T21:00:59.738981+08:00"},{"id":1137,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"bf363deac5ef38c8dc80c73b862e730b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#4-34","gmt_create":"2026-04-23T21:00:59.740313+08:00","gmt_modified":"2026-04-23T21:00:59.740313+08:00"},{"id":1138,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"bf363deac5ef38c8dc80c73b862e730b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-34","gmt_create":"2026-04-23T21:00:59.740555+08:00","gmt_modified":"2026-04-23T21:00:59.740555+08:00"},{"id":1139,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c6e94075e5f689bfa2fe16f8cf965203","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#19-50","gmt_create":"2026-04-23T21:00:59.741293+08:00","gmt_modified":"2026-04-23T21:00:59.741294+08:00"},{"id":1140,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"c6e94075e5f689bfa2fe16f8cf965203","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-50","gmt_create":"2026-04-23T21:00:59.742478+08:00","gmt_modified":"2026-04-23T21:00:59.742478+08:00"},{"id":1141,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"1a78f5574add6d07a1d7c947dba3f23d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#115-150","gmt_create":"2026-04-23T21:00:59.743043+08:00","gmt_modified":"2026-04-23T21:00:59.743043+08:00"},{"id":1142,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"1a78f5574add6d07a1d7c947dba3f23d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 115-150","gmt_create":"2026-04-23T21:00:59.743435+08:00","gmt_modified":"2026-04-23T21:00:59.743435+08:00"},{"id":1143,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"f6810849c947471a4b45d7ca01ec8c5f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#5-9","gmt_create":"2026-04-23T21:00:59.744058+08:00","gmt_modified":"2026-04-23T21:00:59.744059+08:00"},{"id":1144,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"f6810849c947471a4b45d7ca01ec8c5f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-9","gmt_create":"2026-04-23T21:00:59.744873+08:00","gmt_modified":"2026-04-23T21:00:59.744873+08:00"},{"id":1145,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9f6d9941f3b93e29d714bfec7e83434c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#30-36","gmt_create":"2026-04-23T21:00:59.745431+08:00","gmt_modified":"2026-04-23T21:00:59.745431+08:00"},{"id":1146,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"9f6d9941f3b93e29d714bfec7e83434c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-36","gmt_create":"2026-04-23T21:00:59.745747+08:00","gmt_modified":"2026-04-23T21:00:59.745747+08:00"},{"id":1147,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"669d67125dcddb0756f4ff50a43512c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-13","gmt_create":"2026-04-23T21:00:59.746227+08:00","gmt_modified":"2026-04-23T21:00:59.746227+08:00"},{"id":1148,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"669d67125dcddb0756f4ff50a43512c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-13","gmt_create":"2026-04-23T21:00:59.746456+08:00","gmt_modified":"2026-04-23T21:00:59.746456+08:00"},{"id":1149,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-04-23T21:02:44.176751+08:00","gmt_modified":"2026-04-23T21:02:44.176752+08:00"},{"id":1150,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-04-23T21:02:44.178412+08:00","gmt_modified":"2026-04-23T21:02:44.178412+08:00"},{"id":1151,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"80a0429cc47931de27ddb17a62b8dd9c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_business_flow.py","gmt_create":"2026-04-23T21:02:44.178822+08:00","gmt_modified":"2026-04-23T21:02:44.178822+08:00"},{"id":1152,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-04-23T21:02:44.179239+08:00","gmt_modified":"2026-04-23T21:02:44.179239+08:00"},{"id":1153,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"42ff5383133d176cec9eb88682483be3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citations.py","gmt_create":"2026-04-23T21:02:44.180317+08:00","gmt_modified":"2026-04-23T21:02:44.180317+08:00"},{"id":1154,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-04-23T21:02:44.181814+08:00","gmt_modified":"2026-04-23T21:02:44.181814+08:00"},{"id":1155,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-04-23T21:02:44.182497+08:00","gmt_modified":"2026-04-23T21:02:44.182497+08:00"},{"id":1156,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T21:02:44.183181+08:00","gmt_modified":"2026-04-23T21:02:44.183181+08:00"},{"id":1157,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-23T21:02:44.18439+08:00","gmt_modified":"2026-04-23T21:02:44.184391+08:00"},{"id":1158,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-23T21:02:44.185381+08:00","gmt_modified":"2026-04-23T21:02:44.185381+08:00"},{"id":1159,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T21:02:44.186205+08:00","gmt_modified":"2026-04-23T21:02:44.186205+08:00"},{"id":1160,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T21:02:44.186821+08:00","gmt_modified":"2026-04-23T21:02:44.186821+08:00"},{"id":1161,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-23T21:02:44.187337+08:00","gmt_modified":"2026-04-23T21:02:44.187337+08:00"},{"id":1162,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T21:02:44.187931+08:00","gmt_modified":"2026-04-23T21:02:44.187931+08:00"},{"id":1163,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T21:02:44.189534+08:00","gmt_modified":"2026-04-23T21:02:44.189534+08:00"},{"id":1164,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T21:02:44.190082+08:00","gmt_modified":"2026-04-23T21:02:44.190082+08:00"},{"id":1165,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T21:02:44.191061+08:00","gmt_modified":"2026-04-23T21:02:44.191061+08:00"},{"id":1166,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-123","gmt_create":"2026-04-23T21:02:44.191818+08:00","gmt_modified":"2026-04-23T21:02:44.191818+08:00"},{"id":1167,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"85792f0b1e34b5b48b0300aa606ed6e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-56","gmt_create":"2026-04-23T21:02:44.193519+08:00","gmt_modified":"2026-04-23T21:02:44.193519+08:00"},{"id":1168,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"85792f0b1e34b5b48b0300aa606ed6e6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-56","gmt_create":"2026-04-23T21:02:44.193893+08:00","gmt_modified":"2026-04-23T21:02:44.193893+08:00"},{"id":1169,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-04-23T21:02:44.19465+08:00","gmt_modified":"2026-04-23T21:02:44.19465+08:00"},{"id":1170,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-04-23T21:02:44.196035+08:00","gmt_modified":"2026-04-23T21:02:44.196035+08:00"},{"id":1171,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-23T21:02:44.196664+08:00","gmt_modified":"2026-04-23T21:02:44.196664+08:00"},{"id":1172,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T21:02:44.197331+08:00","gmt_modified":"2026-04-23T21:02:44.197331+08:00"},{"id":1173,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-23T21:02:44.198546+08:00","gmt_modified":"2026-04-23T21:02:44.198546+08:00"},{"id":1174,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9630036e63fc15cb81b202cf79671aab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-182","gmt_create":"2026-04-23T21:02:44.201418+08:00","gmt_modified":"2026-04-23T21:02:44.201418+08:00"},{"id":1175,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T21:02:44.204845+08:00","gmt_modified":"2026-04-23T21:02:44.204845+08:00"},{"id":1176,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-23T21:02:44.206431+08:00","gmt_modified":"2026-04-23T21:02:44.206431+08:00"},{"id":1177,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#19-123","gmt_create":"2026-04-23T21:02:44.209024+08:00","gmt_modified":"2026-04-23T21:02:44.209024+08:00"},{"id":1178,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9df233ef1be4b95068ed91bf01083ae7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#117-123","gmt_create":"2026-04-23T21:02:44.210394+08:00","gmt_modified":"2026-04-23T21:02:44.210394+08:00"},{"id":1179,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-04-23T21:02:44.211434+08:00","gmt_modified":"2026-04-23T21:02:44.211434+08:00"},{"id":1180,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-04-23T21:02:44.21293+08:00","gmt_modified":"2026-04-23T21:02:44.21293+08:00"},{"id":1181,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#13-43","gmt_create":"2026-04-23T21:02:44.214312+08:00","gmt_modified":"2026-04-23T21:02:44.214312+08:00"},{"id":1182,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T21:02:44.214737+08:00","gmt_modified":"2026-04-23T21:02:44.214737+08:00"},{"id":1183,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"735aef72b4fe6ca4f407e69b7dda8b43","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-78","gmt_create":"2026-04-23T21:02:44.215146+08:00","gmt_modified":"2026-04-23T21:02:44.215146+08:00"},{"id":1184,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8128dd67cf376d2cadf7c2d3831c380a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#23-29","gmt_create":"2026-04-23T21:02:44.215569+08:00","gmt_modified":"2026-04-23T21:02:44.215569+08:00"},{"id":1185,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-104","gmt_create":"2026-04-23T21:02:44.216343+08:00","gmt_modified":"2026-04-23T21:02:44.216343+08:00"},{"id":1186,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"753a437d837246ead62b0e16c6331284","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-69","gmt_create":"2026-04-23T21:02:44.217942+08:00","gmt_modified":"2026-04-23T21:02:44.217942+08:00"},{"id":1187,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#1-104","gmt_create":"2026-04-23T21:02:44.218781+08:00","gmt_modified":"2026-04-23T21:02:44.218781+08:00"},{"id":1188,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-69","gmt_create":"2026-04-23T21:02:44.219529+08:00","gmt_modified":"2026-04-23T21:02:44.219529+08:00"},{"id":1189,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-120","gmt_create":"2026-04-23T21:02:44.220324+08:00","gmt_modified":"2026-04-23T21:02:44.220324+08:00"},{"id":1190,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#122-146","gmt_create":"2026-04-23T21:02:44.220747+08:00","gmt_modified":"2026-04-23T21:02:44.220748+08:00"},{"id":1191,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T21:02:44.221252+08:00","gmt_modified":"2026-04-23T21:02:44.221252+08:00"},{"id":1192,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"a57acd9da5287c915ac823784a409292","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#1-127","gmt_create":"2026-04-23T21:02:44.221767+08:00","gmt_modified":"2026-04-23T21:02:44.221767+08:00"},{"id":1193,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#23-93","gmt_create":"2026-04-23T21:02:44.222579+08:00","gmt_modified":"2026-04-23T21:02:44.222579+08:00"},{"id":1194,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"692ac240965eff7e66945aa3c4c270f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#1-93","gmt_create":"2026-04-23T21:02:44.22325+08:00","gmt_modified":"2026-04-23T21:02:44.22325+08:00"},{"id":1195,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"32a0a52faca2d8d488e49c63c86075b1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#29-154","gmt_create":"2026-04-23T21:02:44.224171+08:00","gmt_modified":"2026-04-23T21:02:44.224171+08:00"},{"id":1196,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#1-154","gmt_create":"2026-04-23T21:02:44.224941+08:00","gmt_modified":"2026-04-23T21:02:44.224941+08:00"},{"id":1197,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"3a6e1b738967bf8cc651e57f48e2e126","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#83-126","gmt_create":"2026-04-23T21:02:44.225635+08:00","gmt_modified":"2026-04-23T21:02:44.225635+08:00"},{"id":1198,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b1afd377757f1d0e9bdf87edfff3ad88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#131-186","gmt_create":"2026-04-23T21:02:44.226111+08:00","gmt_modified":"2026-04-23T21:02:44.226111+08:00"},{"id":1199,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"de05ec7eed033e432991e5a88e1b5a06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#192-222","gmt_create":"2026-04-23T21:02:44.22649+08:00","gmt_modified":"2026-04-23T21:02:44.22649+08:00"},{"id":1200,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7fd61a451248b6b129299d6246f711c7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#228-296","gmt_create":"2026-04-23T21:02:44.226892+08:00","gmt_modified":"2026-04-23T21:02:44.226892+08:00"},{"id":1201,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"53eedffff456a566fa7b0cecc7169f56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#1-441","gmt_create":"2026-04-23T21:02:44.227356+08:00","gmt_modified":"2026-04-23T21:02:44.227356+08:00"},{"id":1202,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"906f7a8288e38d4244211f3f538fe7b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#27-182","gmt_create":"2026-04-23T21:02:44.227899+08:00","gmt_modified":"2026-04-23T21:02:44.227899+08:00"},{"id":1203,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1647ee2066de2ae59ba8cf88e33c5e02","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_scheduler.py#1-123","gmt_create":"2026-04-23T21:02:44.228365+08:00","gmt_modified":"2026-04-23T21:02:44.228365+08:00"},{"id":1204,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"13c568d2-dfa7-4d1b-81c0-dfef247cbb67","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 13c568d2-dfa7-4d1b-81c0-dfef247cbb67","gmt_create":"2026-04-23T21:02:45.18694+08:00","gmt_modified":"2026-04-23T21:02:45.18694+08:00"},{"id":1205,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"222a9371-45c1-4e0d-b1da-e8ada1c501c2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 222a9371-45c1-4e0d-b1da-e8ada1c501c2","gmt_create":"2026-04-23T21:02:45.187426+08:00","gmt_modified":"2026-04-23T21:02:45.187426+08:00"},{"id":1206,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"979be617-a83d-4db9-b73e-38581348f8c1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 979be617-a83d-4db9-b73e-38581348f8c1","gmt_create":"2026-04-23T21:02:45.187832+08:00","gmt_modified":"2026-04-23T21:02:45.187832+08:00"},{"id":1207,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"422c46b3-e69c-4023-a878-411a48ae182f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 422c46b3-e69c-4023-a878-411a48ae182f","gmt_create":"2026-04-23T21:02:45.188275+08:00","gmt_modified":"2026-04-23T21:02:45.188275+08:00"},{"id":1208,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","gmt_create":"2026-04-23T21:02:45.190159+08:00","gmt_modified":"2026-04-23T21:02:45.190159+08:00"},{"id":1209,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8c17b44f-1586-459b-a83d-c9b961cd2142","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 8c17b44f-1586-459b-a83d-c9b961cd2142","gmt_create":"2026-04-23T21:02:45.191275+08:00","gmt_modified":"2026-04-23T21:02:45.191275+08:00"},{"id":1210,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"05e59a75-d52f-42e1-a924-f6a32f06f2fe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 05e59a75-d52f-42e1-a924-f6a32f06f2fe","gmt_create":"2026-04-23T21:02:45.191685+08:00","gmt_modified":"2026-04-23T21:02:45.191685+08:00"},{"id":1211,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ed630a36e81abafd12787d4095dfe8c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/README.md","gmt_create":"2026-04-24T10:58:35.359267+08:00","gmt_modified":"2026-04-24T10:58:35.359267+08:00"},{"id":1212,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"1cafc02d1d722feb4692dab6ae85c09f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/README.md","gmt_create":"2026-04-24T10:58:35.360113+08:00","gmt_modified":"2026-04-24T10:58:35.360113+08:00"},{"id":1213,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T10:58:35.36047+08:00","gmt_modified":"2026-04-24T10:58:35.36047+08:00"},{"id":1214,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T10:58:35.360788+08:00","gmt_modified":"2026-04-24T10:58:35.360788+08:00"},{"id":1215,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-24T10:58:35.361116+08:00","gmt_modified":"2026-04-24T10:58:35.361116+08:00"},{"id":1216,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-24T10:58:35.385327+08:00","gmt_modified":"2026-04-24T10:58:35.385328+08:00"},{"id":1217,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-24T10:58:35.386483+08:00","gmt_modified":"2026-04-24T10:58:35.386484+08:00"},{"id":1218,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-24T10:58:35.386836+08:00","gmt_modified":"2026-04-24T10:58:35.386836+08:00"},{"id":1219,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-24T10:58:35.387135+08:00","gmt_modified":"2026-04-24T10:58:35.387135+08:00"},{"id":1220,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-24T10:58:35.387467+08:00","gmt_modified":"2026-04-24T10:58:35.387467+08:00"},{"id":1221,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-24T10:58:35.38776+08:00","gmt_modified":"2026-04-24T10:58:35.38776+08:00"},{"id":1222,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-24T10:58:35.388086+08:00","gmt_modified":"2026-04-24T10:58:35.388086+08:00"},{"id":1223,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"f1a7d61831cc0a45ac6220294f15c21d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-24T10:58:35.388419+08:00","gmt_modified":"2026-04-24T10:58:35.388419+08:00"},{"id":1224,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-24T10:58:35.3887+08:00","gmt_modified":"2026-04-24T10:58:35.3887+08:00"},{"id":1225,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-04-24T10:58:35.388982+08:00","gmt_modified":"2026-04-24T10:58:35.388982+08:00"},{"id":1226,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-24T10:58:35.389271+08:00","gmt_modified":"2026-04-24T10:58:35.389271+08:00"},{"id":1227,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-24T10:58:35.389707+08:00","gmt_modified":"2026-04-24T10:58:35.389707+08:00"},{"id":1228,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-04-24T10:58:35.390068+08:00","gmt_modified":"2026-04-24T10:58:35.390068+08:00"},{"id":1229,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-04-24T10:58:35.390413+08:00","gmt_modified":"2026-04-24T10:58:35.390413+08:00"},{"id":1230,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-04-24T10:58:35.390888+08:00","gmt_modified":"2026-04-24T10:58:35.390888+08:00"},{"id":1231,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-84","gmt_create":"2026-04-24T10:58:35.39137+08:00","gmt_modified":"2026-04-24T10:58:35.39137+08:00"},{"id":1232,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-84","gmt_create":"2026-04-24T10:58:35.391735+08:00","gmt_modified":"2026-04-24T10:58:35.391735+08:00"},{"id":1233,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-24T10:58:35.393449+08:00","gmt_modified":"2026-04-24T10:58:35.393449+08:00"},{"id":1234,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-24T10:58:35.394311+08:00","gmt_modified":"2026-04-24T10:58:35.394312+08:00"},{"id":1235,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-04-24T10:58:35.395171+08:00","gmt_modified":"2026-04-24T10:58:35.395171+08:00"},{"id":1236,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-24T10:58:35.397907+08:00","gmt_modified":"2026-04-24T10:58:35.397907+08:00"},{"id":1237,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-24T10:58:35.399232+08:00","gmt_modified":"2026-04-24T10:58:35.399232+08:00"},{"id":1238,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-24T10:58:35.400157+08:00","gmt_modified":"2026-04-24T10:58:35.400157+08:00"},{"id":1239,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-24T10:58:35.400997+08:00","gmt_modified":"2026-04-24T10:58:35.400997+08:00"},{"id":1240,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-24T10:58:35.401612+08:00","gmt_modified":"2026-04-24T10:58:35.401612+08:00"},{"id":1241,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/platform-chart.tsx#1-68","gmt_create":"2026-04-24T10:58:35.402427+08:00","gmt_modified":"2026-04-24T10:58:35.402427+08:00"},{"id":1242,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-18","gmt_create":"2026-04-24T10:58:35.409328+08:00","gmt_modified":"2026-04-24T10:58:35.409329+08:00"},{"id":1243,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-154","gmt_create":"2026-04-24T10:58:35.410752+08:00","gmt_modified":"2026-04-24T10:58:35.410752+08:00"},{"id":1244,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-154","gmt_create":"2026-04-24T10:58:35.411143+08:00","gmt_modified":"2026-04-24T10:58:35.411143+08:00"},{"id":1245,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#1-73","gmt_create":"2026-04-24T10:58:35.41196+08:00","gmt_modified":"2026-04-24T10:58:35.41196+08:00"},{"id":1246,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-73","gmt_create":"2026-04-24T10:58:35.412876+08:00","gmt_modified":"2026-04-24T10:58:35.412876+08:00"},{"id":1247,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-24T10:58:35.414212+08:00","gmt_modified":"2026-04-24T10:58:35.414212+08:00"},{"id":1248,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"93d8c6a312849c344b6a9713b671840f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-39","gmt_create":"2026-04-24T10:58:35.4148+08:00","gmt_modified":"2026-04-24T10:58:35.4148+08:00"},{"id":1249,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"93d8c6a312849c344b6a9713b671840f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-39","gmt_create":"2026-04-24T10:58:35.415254+08:00","gmt_modified":"2026-04-24T10:58:35.415254+08:00"},{"id":1250,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-24T10:58:35.416275+08:00","gmt_modified":"2026-04-24T10:58:35.416275+08:00"},{"id":1251,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"844b21a35ae39ead76ff8831eb974e5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#81-84","gmt_create":"2026-04-24T10:58:35.417932+08:00","gmt_modified":"2026-04-24T10:58:35.417932+08:00"},{"id":1252,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"844b21a35ae39ead76ff8831eb974e5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 81-84","gmt_create":"2026-04-24T10:58:35.418732+08:00","gmt_modified":"2026-04-24T10:58:35.418732+08:00"},{"id":1253,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"3af33bd686ce3d418e31843cac66f58b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#12-67","gmt_create":"2026-04-24T10:58:35.422407+08:00","gmt_modified":"2026-04-24T10:58:35.422407+08:00"},{"id":1254,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"3af33bd686ce3d418e31843cac66f58b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-67","gmt_create":"2026-04-24T10:58:35.423436+08:00","gmt_modified":"2026-04-24T10:58:35.423436+08:00"},{"id":1255,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"06c6dfcd66159d42fa9b9eafd1e36a04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/README.md#11-34","gmt_create":"2026-04-24T10:58:35.424232+08:00","gmt_modified":"2026-04-24T10:58:35.424232+08:00"},{"id":1256,"source_id":"1cafc02d1d722feb4692dab6ae85c09f","target_id":"06c6dfcd66159d42fa9b9eafd1e36a04","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-34","gmt_create":"2026-04-24T10:58:35.424616+08:00","gmt_modified":"2026-04-24T10:58:35.424616+08:00"},{"id":1257,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"903da86dc3fb26783f45f247d60e9534","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#69-126","gmt_create":"2026-04-24T10:58:35.426243+08:00","gmt_modified":"2026-04-24T10:58:35.426243+08:00"},{"id":1258,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"903da86dc3fb26783f45f247d60e9534","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-126","gmt_create":"2026-04-24T10:58:35.426634+08:00","gmt_modified":"2026-04-24T10:58:35.426634+08:00"},{"id":1259,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"0ffe337a73c8fb7254f3e48932a8ae7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#209-234","gmt_create":"2026-04-24T10:58:35.427155+08:00","gmt_modified":"2026-04-24T10:58:35.427155+08:00"},{"id":1260,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"0ffe337a73c8fb7254f3e48932a8ae7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 209-234","gmt_create":"2026-04-24T10:58:35.427796+08:00","gmt_modified":"2026-04-24T10:58:35.427797+08:00"},{"id":1261,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-123","gmt_create":"2026-04-24T10:58:35.428393+08:00","gmt_modified":"2026-04-24T10:58:35.428393+08:00"},{"id":1262,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#1-104","gmt_create":"2026-04-24T10:58:35.429142+08:00","gmt_modified":"2026-04-24T10:58:35.429142+08:00"},{"id":1263,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"55369db351eb916a3210b22f3d672162","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/README.md#161-170","gmt_create":"2026-04-24T10:58:35.429799+08:00","gmt_modified":"2026-04-24T10:58:35.429799+08:00"},{"id":1264,"source_id":"1cafc02d1d722feb4692dab6ae85c09f","target_id":"55369db351eb916a3210b22f3d672162","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-170","gmt_create":"2026-04-24T10:58:35.430152+08:00","gmt_modified":"2026-04-24T10:58:35.430152+08:00"},{"id":1265,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T10:58:51.090576+08:00","gmt_modified":"2026-04-24T10:58:51.090576+08:00"},{"id":1266,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T10:58:51.091365+08:00","gmt_modified":"2026-04-24T10:58:51.091365+08:00"},{"id":1267,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-24T10:58:51.091737+08:00","gmt_modified":"2026-04-24T10:58:51.091737+08:00"},{"id":1268,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-24T10:58:51.092081+08:00","gmt_modified":"2026-04-24T10:58:51.092082+08:00"},{"id":1269,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-24T10:58:51.09262+08:00","gmt_modified":"2026-04-24T10:58:51.092621+08:00"},{"id":1270,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-24T10:58:51.093031+08:00","gmt_modified":"2026-04-24T10:58:51.093032+08:00"},{"id":1271,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-24T10:58:51.093465+08:00","gmt_modified":"2026-04-24T10:58:51.093465+08:00"},{"id":1272,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f26740f2a1532b38c816663a4f665dbf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/admin.py","gmt_create":"2026-04-24T10:58:51.094698+08:00","gmt_modified":"2026-04-24T10:58:51.094698+08:00"},{"id":1273,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-04-24T10:58:51.095352+08:00","gmt_modified":"2026-04-24T10:58:51.095352+08:00"},{"id":1274,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5386144bf3c668c6fa14481c0d85a214","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/subscriptions.py","gmt_create":"2026-04-24T10:58:51.09625+08:00","gmt_modified":"2026-04-24T10:58:51.09625+08:00"},{"id":1275,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b44632a0f399b2fe2b4daf295a120ec7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/logging_middleware.py","gmt_create":"2026-04-24T10:58:51.096695+08:00","gmt_modified":"2026-04-24T10:58:51.096695+08:00"},{"id":1276,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5883a8ef4fc156d76b71ffdb5ecdf232","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/rate_limit.py","gmt_create":"2026-04-24T10:58:51.097182+08:00","gmt_modified":"2026-04-24T10:58:51.097182+08:00"},{"id":1277,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-24T10:58:51.097544+08:00","gmt_modified":"2026-04-24T10:58:51.097544+08:00"},{"id":1278,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5013cbe89f1c6f03533eb218400cedb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/subscription.py","gmt_create":"2026-04-24T10:58:51.097989+08:00","gmt_modified":"2026-04-24T10:58:51.097989+08:00"},{"id":1279,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-24T10:58:51.098376+08:00","gmt_modified":"2026-04-24T10:58:51.098376+08:00"},{"id":1280,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-24T10:58:51.098703+08:00","gmt_modified":"2026-04-24T10:58:51.098703+08:00"},{"id":1281,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-24T10:58:51.099068+08:00","gmt_modified":"2026-04-24T10:58:51.099068+08:00"},{"id":1282,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-04-24T10:58:51.09939+08:00","gmt_modified":"2026-04-24T10:58:51.09939+08:00"},{"id":1283,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-24T10:58:51.099701+08:00","gmt_modified":"2026-04-24T10:58:51.099701+08:00"},{"id":1284,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-24T10:58:51.100081+08:00","gmt_modified":"2026-04-24T10:58:51.100081+08:00"},{"id":1285,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3809c5ab912511e0e093ba02a4fc918f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/admin.py","gmt_create":"2026-04-24T10:58:51.100379+08:00","gmt_modified":"2026-04-24T10:58:51.100379+08:00"},{"id":1286,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b250fc6c32106a7f3e0c3ad152dfc097","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/subscription.py","gmt_create":"2026-04-24T10:58:51.100715+08:00","gmt_modified":"2026-04-24T10:58:51.100715+08:00"},{"id":1287,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-24T10:58:51.101009+08:00","gmt_modified":"2026-04-24T10:58:51.101009+08:00"},{"id":1288,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-24T10:58:51.101343+08:00","gmt_modified":"2026-04-24T10:58:51.101343+08:00"},{"id":1289,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-24T10:58:51.10249+08:00","gmt_modified":"2026-04-24T10:58:51.10249+08:00"},{"id":1290,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-24T10:58:51.103065+08:00","gmt_modified":"2026-04-24T10:58:51.103065+08:00"},{"id":1291,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-24T10:58:51.103573+08:00","gmt_modified":"2026-04-24T10:58:51.103573+08:00"},{"id":1292,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6c080aba7d0e611bd4e7f268835b630f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/logging_middleware.py#1-24","gmt_create":"2026-04-24T10:58:51.104208+08:00","gmt_modified":"2026-04-24T10:58:51.104208+08:00"},{"id":1293,"source_id":"b44632a0f399b2fe2b4daf295a120ec7","target_id":"6c080aba7d0e611bd4e7f268835b630f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-24","gmt_create":"2026-04-24T10:58:51.104849+08:00","gmt_modified":"2026-04-24T10:58:51.104849+08:00"},{"id":1294,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"a7bba55ddc4dd5d215e881e8432d83ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#1-83","gmt_create":"2026-04-24T10:58:51.105316+08:00","gmt_modified":"2026-04-24T10:58:51.105316+08:00"},{"id":1295,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"a7bba55ddc4dd5d215e881e8432d83ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-83","gmt_create":"2026-04-24T10:58:51.105611+08:00","gmt_modified":"2026-04-24T10:58:51.105612+08:00"},{"id":1296,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7c7425c51cc43b8840cefd9764b47204","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#1-108","gmt_create":"2026-04-24T10:58:51.106015+08:00","gmt_modified":"2026-04-24T10:58:51.106015+08:00"},{"id":1297,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"7c7425c51cc43b8840cefd9764b47204","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-108","gmt_create":"2026-04-24T10:58:51.106317+08:00","gmt_modified":"2026-04-24T10:58:51.106317+08:00"},{"id":1298,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6e4a52820e780e4b42651a8214ad4493","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#1-75","gmt_create":"2026-04-24T10:58:51.106864+08:00","gmt_modified":"2026-04-24T10:58:51.106864+08:00"},{"id":1299,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"6e4a52820e780e4b42651a8214ad4493","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-75","gmt_create":"2026-04-24T10:58:51.10724+08:00","gmt_modified":"2026-04-24T10:58:51.10724+08:00"},{"id":1300,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4247da3fc00a7e5f8b73775321eccf8e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#1-77","gmt_create":"2026-04-24T10:58:51.107736+08:00","gmt_modified":"2026-04-24T10:58:51.107736+08:00"},{"id":1301,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"4247da3fc00a7e5f8b73775321eccf8e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-77","gmt_create":"2026-04-24T10:58:51.108036+08:00","gmt_modified":"2026-04-24T10:58:51.108036+08:00"},{"id":1302,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#1-188","gmt_create":"2026-04-24T10:58:51.10901+08:00","gmt_modified":"2026-04-24T10:58:51.10901+08:00"},{"id":1303,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-188","gmt_create":"2026-04-24T10:58:51.109999+08:00","gmt_modified":"2026-04-24T10:58:51.109999+08:00"},{"id":1304,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"557281ca025f76d0dc2db67e56b44053","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#1-155","gmt_create":"2026-04-24T10:58:51.110901+08:00","gmt_modified":"2026-04-24T10:58:51.110901+08:00"},{"id":1305,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"557281ca025f76d0dc2db67e56b44053","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-155","gmt_create":"2026-04-24T10:58:51.111471+08:00","gmt_modified":"2026-04-24T10:58:51.111472+08:00"},{"id":1306,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e2d4838e58acc0eee236ef586abab64e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-48","gmt_create":"2026-04-24T10:58:51.112975+08:00","gmt_modified":"2026-04-24T10:58:51.112975+08:00"},{"id":1307,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"e2d4838e58acc0eee236ef586abab64e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-48","gmt_create":"2026-04-24T10:58:51.113574+08:00","gmt_modified":"2026-04-24T10:58:51.113574+08:00"},{"id":1308,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-29","gmt_create":"2026-04-24T10:58:51.114316+08:00","gmt_modified":"2026-04-24T10:58:51.114317+08:00"},{"id":1309,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-29","gmt_create":"2026-04-24T10:58:51.114869+08:00","gmt_modified":"2026-04-24T10:58:51.114869+08:00"},{"id":1310,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"acd9e6c32084e589d5aeb1665d918dfd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#13-43","gmt_create":"2026-04-24T10:58:51.115422+08:00","gmt_modified":"2026-04-24T10:58:51.115422+08:00"},{"id":1311,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"acd9e6c32084e589d5aeb1665d918dfd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-43","gmt_create":"2026-04-24T10:58:51.115783+08:00","gmt_modified":"2026-04-24T10:58:51.115783+08:00"},{"id":1312,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-48","gmt_create":"2026-04-24T10:58:51.116194+08:00","gmt_modified":"2026-04-24T10:58:51.116194+08:00"},{"id":1313,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-48","gmt_create":"2026-04-24T10:58:51.116484+08:00","gmt_modified":"2026-04-24T10:58:51.116484+08:00"},{"id":1314,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#10-83","gmt_create":"2026-04-24T10:58:51.117175+08:00","gmt_modified":"2026-04-24T10:58:51.117175+08:00"},{"id":1315,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-83","gmt_create":"2026-04-24T10:58:51.117511+08:00","gmt_modified":"2026-04-24T10:58:51.117511+08:00"},{"id":1316,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9357a0fcca02068d428f4a191d08fdcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/logging_middleware.py#8-24","gmt_create":"2026-04-24T10:58:51.117972+08:00","gmt_modified":"2026-04-24T10:58:51.117972+08:00"},{"id":1317,"source_id":"b44632a0f399b2fe2b4daf295a120ec7","target_id":"9357a0fcca02068d428f4a191d08fdcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-24","gmt_create":"2026-04-24T10:58:51.118728+08:00","gmt_modified":"2026-04-24T10:58:51.118728+08:00"},{"id":1318,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-04-24T10:58:51.119241+08:00","gmt_modified":"2026-04-24T10:58:51.119241+08:00"},{"id":1319,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8efcce12915471fe5b88fe058bcf238e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#16-69","gmt_create":"2026-04-24T10:58:51.119743+08:00","gmt_modified":"2026-04-24T10:58:51.119743+08:00"},{"id":1320,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"8efcce12915471fe5b88fe058bcf238e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-69","gmt_create":"2026-04-24T10:58:51.120028+08:00","gmt_modified":"2026-04-24T10:58:51.120028+08:00"},{"id":1321,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-188","gmt_create":"2026-04-24T10:58:51.120577+08:00","gmt_modified":"2026-04-24T10:58:51.120577+08:00"},{"id":1322,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-188","gmt_create":"2026-04-24T10:58:51.124562+08:00","gmt_modified":"2026-04-24T10:58:51.124562+08:00"},{"id":1323,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f4d57f9a78585969a006b7451ea8ce84","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#69-155","gmt_create":"2026-04-24T10:58:51.125327+08:00","gmt_modified":"2026-04-24T10:58:51.125327+08:00"},{"id":1324,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"f4d57f9a78585969a006b7451ea8ce84","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-155","gmt_create":"2026-04-24T10:58:51.125712+08:00","gmt_modified":"2026-04-24T10:58:51.125712+08:00"},{"id":1325,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-24T10:58:51.126301+08:00","gmt_modified":"2026-04-24T10:58:51.126301+08:00"},{"id":1326,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-24T10:58:51.126941+08:00","gmt_modified":"2026-04-24T10:58:51.126941+08:00"},{"id":1327,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-24T10:58:51.127508+08:00","gmt_modified":"2026-04-24T10:58:51.127508+08:00"},{"id":1328,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#86-90","gmt_create":"2026-04-24T10:58:51.128006+08:00","gmt_modified":"2026-04-24T10:58:51.128006+08:00"},{"id":1329,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"608c00e1835ad72363ef08796961faca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-17","gmt_create":"2026-04-24T10:58:51.128784+08:00","gmt_modified":"2026-04-24T10:58:51.128784+08:00"},{"id":1330,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"608c00e1835ad72363ef08796961faca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-17","gmt_create":"2026-04-24T10:58:51.129154+08:00","gmt_modified":"2026-04-24T10:58:51.129154+08:00"},{"id":1331,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#13-43","gmt_create":"2026-04-24T10:58:51.130528+08:00","gmt_modified":"2026-04-24T10:58:51.130528+08:00"},{"id":1332,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"753a437d837246ead62b0e16c6331284","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-69","gmt_create":"2026-04-24T10:58:51.131058+08:00","gmt_modified":"2026-04-24T10:58:51.131059+08:00"},{"id":1333,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-04-24T10:58:51.131916+08:00","gmt_modified":"2026-04-24T10:58:51.131916+08:00"},{"id":1334,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#1-34","gmt_create":"2026-04-24T10:58:51.132407+08:00","gmt_modified":"2026-04-24T10:58:51.132407+08:00"},{"id":1335,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-24T10:58:51.132958+08:00","gmt_modified":"2026-04-24T10:58:51.132958+08:00"},{"id":1336,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-69","gmt_create":"2026-04-24T10:58:51.133552+08:00","gmt_modified":"2026-04-24T10:58:51.133552+08:00"},{"id":1337,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-04-24T10:58:51.134042+08:00","gmt_modified":"2026-04-24T10:58:51.134042+08:00"},{"id":1338,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#26-39","gmt_create":"2026-04-24T10:58:51.134529+08:00","gmt_modified":"2026-04-24T10:58:51.134529+08:00"},{"id":1339,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-24T10:58:51.136504+08:00","gmt_modified":"2026-04-24T10:58:51.136504+08:00"},{"id":1340,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-24T10:58:51.13738+08:00","gmt_modified":"2026-04-24T10:58:51.137381+08:00"},{"id":1341,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ec4bf600a513dc2b014c85e141d7582d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-85","gmt_create":"2026-04-24T10:58:51.138525+08:00","gmt_modified":"2026-04-24T10:58:51.138525+08:00"},{"id":1342,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"ec4bf600a513dc2b014c85e141d7582d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-85","gmt_create":"2026-04-24T10:58:51.139025+08:00","gmt_modified":"2026-04-24T10:58:51.139026+08:00"},{"id":1343,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-24T10:58:51.139644+08:00","gmt_modified":"2026-04-24T10:58:51.139644+08:00"},{"id":1344,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-24T10:58:51.147556+08:00","gmt_modified":"2026-04-24T10:58:51.147556+08:00"},{"id":1345,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-24T10:58:51.148531+08:00","gmt_modified":"2026-04-24T10:58:51.148532+08:00"},{"id":1346,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-24T10:58:51.149856+08:00","gmt_modified":"2026-04-24T10:58:51.149856+08:00"},{"id":1347,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-24T10:58:51.151182+08:00","gmt_modified":"2026-04-24T10:58:51.151182+08:00"},{"id":1348,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-04-24T10:58:51.152306+08:00","gmt_modified":"2026-04-24T10:58:51.152306+08:00"},{"id":1349,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-24T10:58:51.153882+08:00","gmt_modified":"2026-04-24T10:58:51.153882+08:00"},{"id":1350,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-04-24T10:58:51.154802+08:00","gmt_modified":"2026-04-24T10:58:51.154802+08:00"},{"id":1351,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-24T10:58:51.155416+08:00","gmt_modified":"2026-04-24T10:58:51.155416+08:00"},{"id":1352,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-24T10:58:51.155991+08:00","gmt_modified":"2026-04-24T10:58:51.155991+08:00"},{"id":1353,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"86e37040be1aeb400fab9b529f5404c8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#1-37","gmt_create":"2026-04-24T10:58:51.15701+08:00","gmt_modified":"2026-04-24T10:58:51.15701+08:00"},{"id":1354,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-24T10:58:51.157758+08:00","gmt_modified":"2026-04-24T10:58:51.157758+08:00"},{"id":1355,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9606b8243736b4a6f5ecfe152b2ab6dd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#34-83","gmt_create":"2026-04-24T10:58:51.158329+08:00","gmt_modified":"2026-04-24T10:58:51.158329+08:00"},{"id":1356,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"9606b8243736b4a6f5ecfe152b2ab6dd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-83","gmt_create":"2026-04-24T10:58:51.158662+08:00","gmt_modified":"2026-04-24T10:58:51.158662+08:00"},{"id":1357,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-108","gmt_create":"2026-04-24T10:58:51.159846+08:00","gmt_modified":"2026-04-24T10:58:51.159846+08:00"},{"id":1358,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-108","gmt_create":"2026-04-24T10:58:51.160297+08:00","gmt_modified":"2026-04-24T10:58:51.160297+08:00"},{"id":1359,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3d85cad939ce858f9c6d153d425c19fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#25-155","gmt_create":"2026-04-24T10:58:51.162467+08:00","gmt_modified":"2026-04-24T10:58:51.162467+08:00"},{"id":1360,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"3d85cad939ce858f9c6d153d425c19fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-155","gmt_create":"2026-04-24T10:58:51.163075+08:00","gmt_modified":"2026-04-24T10:58:51.163075+08:00"},{"id":1361,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"36769bd305cd5f664fa6e28f82e4b3e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/subscription.py#1-41","gmt_create":"2026-04-24T10:58:51.164182+08:00","gmt_modified":"2026-04-24T10:58:51.164182+08:00"},{"id":1362,"source_id":"5013cbe89f1c6f03533eb218400cedb0","target_id":"36769bd305cd5f664fa6e28f82e4b3e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-24T10:58:51.164477+08:00","gmt_modified":"2026-04-24T10:58:51.164477+08:00"},{"id":1363,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#18-75","gmt_create":"2026-04-24T10:58:51.165828+08:00","gmt_modified":"2026-04-24T10:58:51.165828+08:00"},{"id":1364,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-75","gmt_create":"2026-04-24T10:58:51.166362+08:00","gmt_modified":"2026-04-24T10:58:51.166363+08:00"},{"id":1365,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"eb603ec2611957de67af00756f4b1efa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-13","gmt_create":"2026-04-24T10:58:51.173515+08:00","gmt_modified":"2026-04-24T10:58:51.173515+08:00"},{"id":1366,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#42-90","gmt_create":"2026-04-24T10:58:51.174668+08:00","gmt_modified":"2026-04-24T10:58:51.174668+08:00"},{"id":1367,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#211-227","gmt_create":"2026-04-24T10:58:51.175216+08:00","gmt_modified":"2026-04-24T10:58:51.175216+08:00"},{"id":1368,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-24T10:59:38.925103+08:00","gmt_modified":"2026-04-24T10:59:38.925103+08:00"},{"id":1369,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-24T10:59:38.925495+08:00","gmt_modified":"2026-04-24T10:59:38.925495+08:00"},{"id":1370,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-24T10:59:38.925816+08:00","gmt_modified":"2026-04-24T10:59:38.925816+08:00"},{"id":1371,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-24T10:59:38.926111+08:00","gmt_modified":"2026-04-24T10:59:38.926111+08:00"},{"id":1372,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-24T10:59:38.926454+08:00","gmt_modified":"2026-04-24T10:59:38.926454+08:00"},{"id":1373,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-04-24T10:59:38.926763+08:00","gmt_modified":"2026-04-24T10:59:38.926763+08:00"},{"id":1374,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"99fe1b288fd41daa86c2dfbab819abf0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/__init__.py","gmt_create":"2026-04-24T10:59:38.927067+08:00","gmt_modified":"2026-04-24T10:59:38.927067+08:00"},{"id":1375,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"a680d4819f5da57fe9fa0e6bc708f380","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/env.py","gmt_create":"2026-04-24T10:59:38.927719+08:00","gmt_modified":"2026-04-24T10:59:38.927719+08:00"},{"id":1376,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-24T10:59:38.928116+08:00","gmt_modified":"2026-04-24T10:59:38.928116+08:00"},{"id":1377,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f6e6948dd0cdd3894bd9928b21feb979","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","gmt_create":"2026-04-24T10:59:38.928438+08:00","gmt_modified":"2026-04-24T10:59:38.928438+08:00"},{"id":1378,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b0cb6810919f64006be7aa66b2b76a61","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-04-24T10:59:38.928749+08:00","gmt_modified":"2026-04-24T10:59:38.928749+08:00"},{"id":1379,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic.ini","gmt_create":"2026-04-24T10:59:38.929055+08:00","gmt_modified":"2026-04-24T10:59:38.929055+08:00"},{"id":1380,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T10:59:38.929804+08:00","gmt_modified":"2026-04-24T10:59:38.929804+08:00"},{"id":1381,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-04-24T10:59:38.930168+08:00","gmt_modified":"2026-04-24T10:59:38.930168+08:00"},{"id":1382,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-24T10:59:38.930497+08:00","gmt_modified":"2026-04-24T10:59:38.930497+08:00"},{"id":1383,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-24T10:59:38.9308+08:00","gmt_modified":"2026-04-24T10:59:38.9308+08:00"},{"id":1384,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-24T10:59:38.93116+08:00","gmt_modified":"2026-04-24T10:59:38.93116+08:00"},{"id":1385,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-24T10:59:38.931453+08:00","gmt_modified":"2026-04-24T10:59:38.931453+08:00"},{"id":1386,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-24T10:59:38.931762+08:00","gmt_modified":"2026-04-24T10:59:38.931762+08:00"},{"id":1387,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-24T10:59:38.932057+08:00","gmt_modified":"2026-04-24T10:59:38.932057+08:00"},{"id":1388,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-04-24T10:59:38.932387+08:00","gmt_modified":"2026-04-24T10:59:38.932387+08:00"},{"id":1389,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-24T10:59:38.932782+08:00","gmt_modified":"2026-04-24T10:59:38.932782+08:00"},{"id":1390,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-24T10:59:38.933359+08:00","gmt_modified":"2026-04-24T10:59:38.933359+08:00"},{"id":1391,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1f8d26b6a5da49d89d95bb13c7ace2c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-48","gmt_create":"2026-04-24T10:59:38.93393+08:00","gmt_modified":"2026-04-24T10:59:38.93393+08:00"},{"id":1392,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"1f8d26b6a5da49d89d95bb13c7ace2c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-48","gmt_create":"2026-04-24T10:59:38.934235+08:00","gmt_modified":"2026-04-24T10:59:38.934235+08:00"},{"id":1393,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-24T10:59:38.934687+08:00","gmt_modified":"2026-04-24T10:59:38.934687+08:00"},{"id":1394,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d4f99d3dd9fe489c354edf5fe2f8803d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-44","gmt_create":"2026-04-24T10:59:38.93518+08:00","gmt_modified":"2026-04-24T10:59:38.93518+08:00"},{"id":1395,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-24T10:59:38.935665+08:00","gmt_modified":"2026-04-24T10:59:38.935666+08:00"},{"id":1396,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"86e37040be1aeb400fab9b529f5404c8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#1-37","gmt_create":"2026-04-24T10:59:38.936197+08:00","gmt_modified":"2026-04-24T10:59:38.936197+08:00"},{"id":1397,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"211463f5b49610f09594c40c0a235943","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#1-89","gmt_create":"2026-04-24T10:59:38.936699+08:00","gmt_modified":"2026-04-24T10:59:38.936699+08:00"},{"id":1398,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-04-24T10:59:38.937893+08:00","gmt_modified":"2026-04-24T10:59:38.937893+08:00"},{"id":1399,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/__init__.py#1-14","gmt_create":"2026-04-24T10:59:38.93994+08:00","gmt_modified":"2026-04-24T10:59:38.93994+08:00"},{"id":1400,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"98cc82f62b83678f06a33cf9231ecdf8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#1-128","gmt_create":"2026-04-24T10:59:38.940473+08:00","gmt_modified":"2026-04-24T10:59:38.940474+08:00"},{"id":1401,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"e1aabd52989e47806fb997157381e1cf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#1-37","gmt_create":"2026-04-24T10:59:38.941718+08:00","gmt_modified":"2026-04-24T10:59:38.941719+08:00"},{"id":1402,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c8f2dbcb7475bd189a34c7061ea46c6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#1-41","gmt_create":"2026-04-24T10:59:38.943509+08:00","gmt_modified":"2026-04-24T10:59:38.943509+08:00"},{"id":1403,"source_id":"b0cb6810919f64006be7aa66b2b76a61","target_id":"c8f2dbcb7475bd189a34c7061ea46c6d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-24T10:59:38.943933+08:00","gmt_modified":"2026-04-24T10:59:38.943933+08:00"},{"id":1404,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-130","gmt_create":"2026-04-24T10:59:38.944411+08:00","gmt_modified":"2026-04-24T10:59:38.944411+08:00"},{"id":1405,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-429","gmt_create":"2026-04-24T10:59:38.945012+08:00","gmt_modified":"2026-04-24T10:59:38.945012+08:00"},{"id":1406,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-175","gmt_create":"2026-04-24T10:59:38.945794+08:00","gmt_modified":"2026-04-24T10:59:38.945794+08:00"},{"id":1407,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-175","gmt_create":"2026-04-24T10:59:38.9463+08:00","gmt_modified":"2026-04-24T10:59:38.9463+08:00"},{"id":1408,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-04-24T10:59:38.947657+08:00","gmt_modified":"2026-04-24T10:59:38.947657+08:00"},{"id":1409,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-48","gmt_create":"2026-04-24T10:59:38.947981+08:00","gmt_modified":"2026-04-24T10:59:38.947981+08:00"},{"id":1410,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"bfdf3479f244dc6794628d9df10ab6d0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-48","gmt_create":"2026-04-24T10:59:38.948384+08:00","gmt_modified":"2026-04-24T10:59:38.948384+08:00"},{"id":1411,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f5f9f0d96263ae84631c7a8d7e9b3648","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-44","gmt_create":"2026-04-24T10:59:38.948988+08:00","gmt_modified":"2026-04-24T10:59:38.948988+08:00"},{"id":1412,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"818d1354dc0665798f3d91a2ca5153d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-34","gmt_create":"2026-04-24T10:59:38.949513+08:00","gmt_modified":"2026-04-24T10:59:38.949513+08:00"},{"id":1413,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"24aade4c34609a8ab28e4643a3692201","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-36","gmt_create":"2026-04-24T10:59:38.950006+08:00","gmt_modified":"2026-04-24T10:59:38.950006+08:00"},{"id":1414,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ac77e4875817616194b7b5997d4fb1ae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#57-94","gmt_create":"2026-04-24T10:59:38.951919+08:00","gmt_modified":"2026-04-24T10:59:38.951919+08:00"},{"id":1415,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"0e57efd98dacc85da21f995980371ee4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#21-37","gmt_create":"2026-04-24T10:59:38.952471+08:00","gmt_modified":"2026-04-24T10:59:38.952471+08:00"},{"id":1416,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#21-41","gmt_create":"2026-04-24T10:59:38.953364+08:00","gmt_modified":"2026-04-24T10:59:38.953364+08:00"},{"id":1417,"source_id":"b0cb6810919f64006be7aa66b2b76a61","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-41","gmt_create":"2026-04-24T10:59:38.954222+08:00","gmt_modified":"2026-04-24T10:59:38.954223+08:00"},{"id":1418,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#50-54","gmt_create":"2026-04-24T10:59:38.954734+08:00","gmt_modified":"2026-04-24T10:59:38.954734+08:00"},{"id":1419,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"717eb27184726e4f78d694984d29420c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#37-44","gmt_create":"2026-04-24T10:59:38.955244+08:00","gmt_modified":"2026-04-24T10:59:38.955244+08:00"},{"id":1420,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#36-38","gmt_create":"2026-04-24T10:59:38.95576+08:00","gmt_modified":"2026-04-24T10:59:38.95576+08:00"},{"id":1421,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d34337b9ff77246979252d2fd8fb8018","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#33-88","gmt_create":"2026-04-24T10:59:38.959262+08:00","gmt_modified":"2026-04-24T10:59:38.959262+08:00"},{"id":1422,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#21-128","gmt_create":"2026-04-24T10:59:38.959807+08:00","gmt_modified":"2026-04-24T10:59:38.959807+08:00"},{"id":1423,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"eb63042f04a22f9a67bd498df1684d20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#36-111","gmt_create":"2026-04-24T10:59:38.962943+08:00","gmt_modified":"2026-04-24T10:59:38.962944+08:00"},{"id":1424,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-24T10:59:38.964073+08:00","gmt_modified":"2026-04-24T10:59:38.964073+08:00"},{"id":1425,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c651c7ad6747a92ee96eabb2eb82afdd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#12-18","gmt_create":"2026-04-24T10:59:38.964595+08:00","gmt_modified":"2026-04-24T10:59:38.964595+08:00"},{"id":1426,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"fe351bf59a46bec7f77ffe40a68a5993","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#40-56","gmt_create":"2026-04-24T10:59:38.96518+08:00","gmt_modified":"2026-04-24T10:59:38.96518+08:00"},{"id":1427,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"fe351bf59a46bec7f77ffe40a68a5993","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-56","gmt_create":"2026-04-24T10:59:38.965521+08:00","gmt_modified":"2026-04-24T10:59:38.965521+08:00"},{"id":1428,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7dae7237f11c5100bf7889c105193cf6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-32","gmt_create":"2026-04-24T10:59:38.966015+08:00","gmt_modified":"2026-04-24T10:59:38.966015+08:00"},{"id":1429,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"dd01eee487298a28e950f6345196f1d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#30-79","gmt_create":"2026-04-24T10:59:38.96654+08:00","gmt_modified":"2026-04-24T10:59:38.96654+08:00"},{"id":1430,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"cc64cf609f5ff218f618e0664ffa7cc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#298-308","gmt_create":"2026-04-24T10:59:38.967326+08:00","gmt_modified":"2026-04-24T10:59:38.967326+08:00"},{"id":1431,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ce7e334595a4ce912e0d116314db9a35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#342-429","gmt_create":"2026-04-24T10:59:38.96818+08:00","gmt_modified":"2026-04-24T10:59:38.96818+08:00"},{"id":1432,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-24T10:59:38.968611+08:00","gmt_modified":"2026-04-24T10:59:38.968611+08:00"},{"id":1433,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"2f46f212597e3c245b9e5dcc5dbc863d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-18","gmt_create":"2026-04-24T10:59:38.969663+08:00","gmt_modified":"2026-04-24T10:59:38.969663+08:00"},{"id":1434,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-107","gmt_create":"2026-04-24T10:59:38.970327+08:00","gmt_modified":"2026-04-24T10:59:38.970327+08:00"},{"id":1435,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-107","gmt_create":"2026-04-24T10:59:38.971032+08:00","gmt_modified":"2026-04-24T10:59:38.971032+08:00"},{"id":1436,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#110-140","gmt_create":"2026-04-24T10:59:38.971655+08:00","gmt_modified":"2026-04-24T10:59:38.971655+08:00"},{"id":1437,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 110-140","gmt_create":"2026-04-24T10:59:38.97203+08:00","gmt_modified":"2026-04-24T10:59:38.97203+08:00"},{"id":1438,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1153d8a149a70bc79ca59a9dcba5945c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-55","gmt_create":"2026-04-24T10:59:38.972462+08:00","gmt_modified":"2026-04-24T10:59:38.972462+08:00"},{"id":1439,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"1153d8a149a70bc79ca59a9dcba5945c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-55","gmt_create":"2026-04-24T10:59:38.972843+08:00","gmt_modified":"2026-04-24T10:59:38.972843+08:00"},{"id":1440,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-115","gmt_create":"2026-04-24T10:59:38.973327+08:00","gmt_modified":"2026-04-24T10:59:38.973327+08:00"},{"id":1441,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-115","gmt_create":"2026-04-24T10:59:38.973675+08:00","gmt_modified":"2026-04-24T10:59:38.973675+08:00"},{"id":1442,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"dc40f1dd3e59ee7f046019201068bea1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#14-22","gmt_create":"2026-04-24T10:59:38.978124+08:00","gmt_modified":"2026-04-24T10:59:38.978124+08:00"},{"id":1443,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-24T11:01:58.083117+08:00","gmt_modified":"2026-04-24T11:01:58.083117+08:00"},{"id":1444,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"955e1dfe57f0a9a8e900383eb7641ba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/next.config.mjs","gmt_create":"2026-04-24T11:01:58.083525+08:00","gmt_modified":"2026-04-24T11:01:58.083525+08:00"},{"id":1445,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-04-24T11:01:58.08385+08:00","gmt_modified":"2026-04-24T11:01:58.083851+08:00"},{"id":1446,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-24T11:01:58.084156+08:00","gmt_modified":"2026-04-24T11:01:58.084156+08:00"},{"id":1447,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"546e01c5f73aaf5140eee922f4b9a441","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/providers.tsx","gmt_create":"2026-04-24T11:01:58.084498+08:00","gmt_modified":"2026-04-24T11:01:58.084498+08:00"},{"id":1448,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"5800a08224424ebced854d06365f6d44","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(auth","gmt_create":"2026-04-24T11:01:58.084794+08:00","gmt_modified":"2026-04-24T11:01:58.084794+08:00"},{"id":1449,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-04-24T11:01:58.08511+08:00","gmt_modified":"2026-04-24T11:01:58.08511+08:00"},{"id":1450,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-04-24T11:01:58.085472+08:00","gmt_modified":"2026-04-24T11:01:58.085472+08:00"},{"id":1451,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/types/next-auth.d.ts","gmt_create":"2026-04-24T11:01:58.085769+08:00","gmt_modified":"2026-04-24T11:01:58.085769+08:00"},{"id":1452,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-24T11:01:58.08607+08:00","gmt_modified":"2026-04-24T11:01:58.086071+08:00"},{"id":1453,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"ac1acbc54c49ee1de13369f6c6827568","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/button.tsx","gmt_create":"2026-04-24T11:01:58.087299+08:00","gmt_modified":"2026-04-24T11:01:58.087299+08:00"},{"id":1454,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"eca13a610badfc5ffc6210827fb96991","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/header.tsx","gmt_create":"2026-04-24T11:01:58.087674+08:00","gmt_modified":"2026-04-24T11:01:58.087674+08:00"},{"id":1455,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"18a0651d895fba9bb4e0c0229459efdc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/sidebar.tsx","gmt_create":"2026-04-24T11:01:58.087981+08:00","gmt_modified":"2026-04-24T11:01:58.087981+08:00"},{"id":1456,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"beb87ab5aad9532647e9dbd2db7ef587","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/tabs.tsx","gmt_create":"2026-04-24T11:01:58.088269+08:00","gmt_modified":"2026-04-24T11:01:58.088269+08:00"},{"id":1457,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"facea1f00ec72e00f774d0839fee7131","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: /Users/Chiguyong/Code/GEO#wiki#main#wiki#zh/[app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","gmt_create":"2026-04-24T11:01:58.088559+08:00","gmt_modified":"2026-04-24T11:01:58.088559+08:00"},{"id":1458,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-24T11:01:58.088994+08:00","gmt_modified":"2026-04-24T11:01:58.088994+08:00"},{"id":1459,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"fd18328b6582e68c30b130b912891992","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/providers.tsx#1-9","gmt_create":"2026-04-24T11:01:58.089491+08:00","gmt_modified":"2026-04-24T11:01:58.089491+08:00"},{"id":1460,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"dc735ee4a0f12140bcee122a67f4a13b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/sidebar.tsx#1-63","gmt_create":"2026-04-24T11:01:58.089973+08:00","gmt_modified":"2026-04-24T11:01:58.089973+08:00"},{"id":1461,"source_id":"18a0651d895fba9bb4e0c0229459efdc","target_id":"dc735ee4a0f12140bcee122a67f4a13b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-63","gmt_create":"2026-04-24T11:01:58.090246+08:00","gmt_modified":"2026-04-24T11:01:58.090246+08:00"},{"id":1462,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#1-56","gmt_create":"2026-04-24T11:01:58.090695+08:00","gmt_modified":"2026-04-24T11:01:58.090695+08:00"},{"id":1463,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-57","gmt_create":"2026-04-24T11:01:58.091173+08:00","gmt_modified":"2026-04-24T11:01:58.091173+08:00"},{"id":1464,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"f990ecd63842b3ab82f5b8c8dcde2a6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/next.config.mjs#1-5","gmt_create":"2026-04-24T11:01:58.091728+08:00","gmt_modified":"2026-04-24T11:01:58.091729+08:00"},{"id":1465,"source_id":"955e1dfe57f0a9a8e900383eb7641ba1","target_id":"f990ecd63842b3ab82f5b8c8dcde2a6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-5","gmt_create":"2026-04-24T11:01:58.092029+08:00","gmt_modified":"2026-04-24T11:01:58.092029+08:00"},{"id":1466,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#1-73","gmt_create":"2026-04-24T11:01:58.094426+08:00","gmt_modified":"2026-04-24T11:01:58.094426+08:00"},{"id":1467,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"d5efa0fbc545b778dd913854d860c502","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/types/next-auth.d.ts#1-29","gmt_create":"2026-04-24T11:01:58.094992+08:00","gmt_modified":"2026-04-24T11:01:58.094992+08:00"},{"id":1468,"source_id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","target_id":"d5efa0fbc545b778dd913854d860c502","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-04-24T11:01:58.095303+08:00","gmt_modified":"2026-04-24T11:01:58.095304+08:00"},{"id":1469,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-154","gmt_create":"2026-04-24T11:01:58.095866+08:00","gmt_modified":"2026-04-24T11:01:58.095867+08:00"},{"id":1470,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#1-57","gmt_create":"2026-04-24T11:01:58.096403+08:00","gmt_modified":"2026-04-24T11:01:58.096403+08:00"},{"id":1471,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/header.tsx#1-30","gmt_create":"2026-04-24T11:01:58.096919+08:00","gmt_modified":"2026-04-24T11:01:58.096919+08:00"},{"id":1472,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-24T11:01:58.105424+08:00","gmt_modified":"2026-04-24T11:01:58.105424+08:00"},{"id":1473,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-24T11:02:17.577219+08:00","gmt_modified":"2026-04-24T11:02:17.577219+08:00"},{"id":1474,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-24T11:02:17.578316+08:00","gmt_modified":"2026-04-24T11:02:17.578316+08:00"},{"id":1475,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-24T11:02:17.579016+08:00","gmt_modified":"2026-04-24T11:02:17.579016+08:00"},{"id":1476,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-24T11:02:17.579604+08:00","gmt_modified":"2026-04-24T11:02:17.579604+08:00"},{"id":1477,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-24T11:02:17.580669+08:00","gmt_modified":"2026-04-24T11:02:17.580669+08:00"},{"id":1478,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T11:02:17.581765+08:00","gmt_modified":"2026-04-24T11:02:17.581765+08:00"},{"id":1479,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-24T11:02:17.582245+08:00","gmt_modified":"2026-04-24T11:02:17.582245+08:00"},{"id":1480,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T11:02:17.582573+08:00","gmt_modified":"2026-04-24T11:02:17.582573+08:00"},{"id":1481,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-24T11:02:17.582943+08:00","gmt_modified":"2026-04-24T11:02:17.582943+08:00"},{"id":1482,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b0cb6810919f64006be7aa66b2b76a61","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-04-24T11:02:17.58335+08:00","gmt_modified":"2026-04-24T11:02:17.58335+08:00"},{"id":1483,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-04-24T11:02:17.583672+08:00","gmt_modified":"2026-04-24T11:02:17.583673+08:00"},{"id":1484,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-24T11:02:17.583973+08:00","gmt_modified":"2026-04-24T11:02:17.583973+08:00"},{"id":1485,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5800a08224424ebced854d06365f6d44","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(auth","gmt_create":"2026-04-24T11:02:17.584307+08:00","gmt_modified":"2026-04-24T11:02:17.584307+08:00"},{"id":1486,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"37d7291b1373216dcf08f081a94ab1c8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: /Users/Chiguyong/Code/GEO#wiki#main#wiki#zh/[frontend/app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","gmt_create":"2026-04-24T11:02:17.585037+08:00","gmt_modified":"2026-04-24T11:02:17.585037+08:00"},{"id":1487,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-04-24T11:02:17.585369+08:00","gmt_modified":"2026-04-24T11:02:17.585369+08:00"},{"id":1488,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-04-24T11:02:17.585874+08:00","gmt_modified":"2026-04-24T11:02:17.585874+08:00"},{"id":1489,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46434c04e402674d97a6e2017a3a13c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-62","gmt_create":"2026-04-24T11:02:17.58637+08:00","gmt_modified":"2026-04-24T11:02:17.58637+08:00"},{"id":1490,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"46434c04e402674d97a6e2017a3a13c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-62","gmt_create":"2026-04-24T11:02:17.586722+08:00","gmt_modified":"2026-04-24T11:02:17.586723+08:00"},{"id":1491,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"3a0fd619768c80d413f8b02b3daec229","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-175","gmt_create":"2026-04-24T11:02:17.587241+08:00","gmt_modified":"2026-04-24T11:02:17.587241+08:00"},{"id":1492,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"3a0fd619768c80d413f8b02b3daec229","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-175","gmt_create":"2026-04-24T11:02:17.587532+08:00","gmt_modified":"2026-04-24T11:02:17.587532+08:00"},{"id":1493,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"86af0295eebcd62f33207e158db86c81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-115","gmt_create":"2026-04-24T11:02:17.58823+08:00","gmt_modified":"2026-04-24T11:02:17.58823+08:00"},{"id":1494,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"86af0295eebcd62f33207e158db86c81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-115","gmt_create":"2026-04-24T11:02:17.588592+08:00","gmt_modified":"2026-04-24T11:02:17.588592+08:00"},{"id":1495,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#21-41","gmt_create":"2026-04-24T11:02:17.589011+08:00","gmt_modified":"2026-04-24T11:02:17.589011+08:00"},{"id":1496,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"809fc86e3ce390a1af1db1e0cd5ad787","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#55-84","gmt_create":"2026-04-24T11:02:17.589558+08:00","gmt_modified":"2026-04-24T11:02:17.589558+08:00"},{"id":1497,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"809fc86e3ce390a1af1db1e0cd5ad787","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 55-84","gmt_create":"2026-04-24T11:02:17.589968+08:00","gmt_modified":"2026-04-24T11:02:17.589968+08:00"},{"id":1498,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-48","gmt_create":"2026-04-24T11:02:17.590369+08:00","gmt_modified":"2026-04-24T11:02:17.590369+08:00"},{"id":1499,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-04-24T11:02:17.591152+08:00","gmt_modified":"2026-04-24T11:02:17.591152+08:00"},{"id":1500,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"608c00e1835ad72363ef08796961faca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-17","gmt_create":"2026-04-24T11:02:17.59504+08:00","gmt_modified":"2026-04-24T11:02:17.59504+08:00"},{"id":1501,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-29","gmt_create":"2026-04-24T11:02:17.595846+08:00","gmt_modified":"2026-04-24T11:02:17.595846+08:00"},{"id":1502,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"29ee02d164db08d7b9bd4591195e191b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#5-56","gmt_create":"2026-04-24T11:02:17.596584+08:00","gmt_modified":"2026-04-24T11:02:17.596584+08:00"},{"id":1503,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"29ee02d164db08d7b9bd4591195e191b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-56","gmt_create":"2026-04-24T11:02:17.596923+08:00","gmt_modified":"2026-04-24T11:02:17.596923+08:00"},{"id":1504,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"73c4889fcacaea737921a568bf20383d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#13-32","gmt_create":"2026-04-24T11:02:17.598958+08:00","gmt_modified":"2026-04-24T11:02:17.598958+08:00"},{"id":1505,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"73c4889fcacaea737921a568bf20383d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-32","gmt_create":"2026-04-24T11:02:17.599388+08:00","gmt_modified":"2026-04-24T11:02:17.599389+08:00"},{"id":1506,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"11c2505e56ba9a48c50be4c915f22c9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#27-37","gmt_create":"2026-04-24T11:02:17.601161+08:00","gmt_modified":"2026-04-24T11:02:17.601161+08:00"},{"id":1507,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"11c2505e56ba9a48c50be4c915f22c9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-37","gmt_create":"2026-04-24T11:02:17.601545+08:00","gmt_modified":"2026-04-24T11:02:17.601545+08:00"},{"id":1508,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5f32b18b18cea3b2bdc9150366c24e5e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#26-37","gmt_create":"2026-04-24T11:02:17.601968+08:00","gmt_modified":"2026-04-24T11:02:17.601968+08:00"},{"id":1509,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"5f32b18b18cea3b2bdc9150366c24e5e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-37","gmt_create":"2026-04-24T11:02:17.602636+08:00","gmt_modified":"2026-04-24T11:02:17.602636+08:00"},{"id":1510,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c4abaa8a82ad75d09ee66f97fbad4b96","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-10","gmt_create":"2026-04-24T11:02:17.603102+08:00","gmt_modified":"2026-04-24T11:02:17.603102+08:00"},{"id":1511,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"c4abaa8a82ad75d09ee66f97fbad4b96","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-10","gmt_create":"2026-04-24T11:02:17.603401+08:00","gmt_modified":"2026-04-24T11:02:17.603402+08:00"},{"id":1512,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"08ac91fb508b386f0e6c66e53b03a471","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-11","gmt_create":"2026-04-24T11:02:17.604811+08:00","gmt_modified":"2026-04-24T11:02:17.604811+08:00"},{"id":1513,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"08ac91fb508b386f0e6c66e53b03a471","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-11","gmt_create":"2026-04-24T11:02:17.60518+08:00","gmt_modified":"2026-04-24T11:02:17.60518+08:00"},{"id":1514,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d4ea500c0acb4ebf267a44908e23f787","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#40-55","gmt_create":"2026-04-24T11:02:17.605584+08:00","gmt_modified":"2026-04-24T11:02:17.605584+08:00"},{"id":1515,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"d4ea500c0acb4ebf267a44908e23f787","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-55","gmt_create":"2026-04-24T11:02:17.605874+08:00","gmt_modified":"2026-04-24T11:02:17.605874+08:00"},{"id":1516,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b4f0bea37f71296167571d8831ebe6d5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-58","gmt_create":"2026-04-24T11:02:17.60772+08:00","gmt_modified":"2026-04-24T11:02:17.607721+08:00"},{"id":1517,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"b4f0bea37f71296167571d8831ebe6d5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-58","gmt_create":"2026-04-24T11:02:17.608058+08:00","gmt_modified":"2026-04-24T11:02:17.608058+08:00"},{"id":1518,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46f7431da5eb82bbd7686a71abaddf78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#42-57","gmt_create":"2026-04-24T11:02:17.608532+08:00","gmt_modified":"2026-04-24T11:02:17.608532+08:00"},{"id":1519,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"46f7431da5eb82bbd7686a71abaddf78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-57","gmt_create":"2026-04-24T11:02:17.608872+08:00","gmt_modified":"2026-04-24T11:02:17.608872+08:00"},{"id":1520,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"0ba2ea54873608360c48c8b5aaeea20f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#58-71","gmt_create":"2026-04-24T11:02:17.609376+08:00","gmt_modified":"2026-04-24T11:02:17.609376+08:00"},{"id":1521,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"0ba2ea54873608360c48c8b5aaeea20f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 58-71","gmt_create":"2026-04-24T11:02:17.609794+08:00","gmt_modified":"2026-04-24T11:02:17.609794+08:00"},{"id":1522,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"2d170933ae8c838199f6d68a2b9165c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#61-84","gmt_create":"2026-04-24T11:02:17.610895+08:00","gmt_modified":"2026-04-24T11:02:17.610895+08:00"},{"id":1523,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"2d170933ae8c838199f6d68a2b9165c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-84","gmt_create":"2026-04-24T11:02:17.6112+08:00","gmt_modified":"2026-04-24T11:02:17.6112+08:00"},{"id":1524,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"0ea85b56099b9087bd22eec96b7bb752","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-140","gmt_create":"2026-04-24T11:02:17.611696+08:00","gmt_modified":"2026-04-24T11:02:17.611696+08:00"},{"id":1525,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"0ea85b56099b9087bd22eec96b7bb752","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-140","gmt_create":"2026-04-24T11:02:17.612307+08:00","gmt_modified":"2026-04-24T11:02:17.612307+08:00"},{"id":1526,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"2a4087b6941ca17dd651147f2f23451c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-90","gmt_create":"2026-04-24T11:02:17.613704+08:00","gmt_modified":"2026-04-24T11:02:17.613704+08:00"},{"id":1527,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"2a4087b6941ca17dd651147f2f23451c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-90","gmt_create":"2026-04-24T11:02:17.614071+08:00","gmt_modified":"2026-04-24T11:02:17.614071+08:00"},{"id":1528,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"88c12e200d5c3ea53c695aa4209cecd9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-76","gmt_create":"2026-04-24T11:02:17.614574+08:00","gmt_modified":"2026-04-24T11:02:17.614574+08:00"},{"id":1529,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"88c12e200d5c3ea53c695aa4209cecd9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-76","gmt_create":"2026-04-24T11:02:17.615017+08:00","gmt_modified":"2026-04-24T11:02:17.615017+08:00"},{"id":1530,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#110-140","gmt_create":"2026-04-24T11:02:17.615713+08:00","gmt_modified":"2026-04-24T11:02:17.615713+08:00"},{"id":1531,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"42b92d878423a23067e9a6da104e3a5e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#79-90","gmt_create":"2026-04-24T11:02:17.616887+08:00","gmt_modified":"2026-04-24T11:02:17.616888+08:00"},{"id":1532,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"42b92d878423a23067e9a6da104e3a5e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-90","gmt_create":"2026-04-24T11:02:17.617309+08:00","gmt_modified":"2026-04-24T11:02:17.617309+08:00"},{"id":1533,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-107","gmt_create":"2026-04-24T11:02:17.617785+08:00","gmt_modified":"2026-04-24T11:02:17.617785+08:00"},{"id":1534,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"abadc99952ad6e00ab4bfb66b84732bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#33-41","gmt_create":"2026-04-24T11:02:17.618924+08:00","gmt_modified":"2026-04-24T11:02:17.618925+08:00"},{"id":1535,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"abadc99952ad6e00ab4bfb66b84732bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-41","gmt_create":"2026-04-24T11:02:17.619333+08:00","gmt_modified":"2026-04-24T11:02:17.619333+08:00"},{"id":1536,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f784a33e47128515d518555d99103f62","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#143-175","gmt_create":"2026-04-24T11:02:17.619742+08:00","gmt_modified":"2026-04-24T11:02:17.619742+08:00"},{"id":1537,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"f784a33e47128515d518555d99103f62","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 143-175","gmt_create":"2026-04-24T11:02:17.620025+08:00","gmt_modified":"2026-04-24T11:02:17.620025+08:00"},{"id":1538,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"173f8de5896e18fc81cdd5d72e2a8c07","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#93-115","gmt_create":"2026-04-24T11:02:17.621068+08:00","gmt_modified":"2026-04-24T11:02:17.621068+08:00"},{"id":1539,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"173f8de5896e18fc81cdd5d72e2a8c07","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 93-115","gmt_create":"2026-04-24T11:02:17.62207+08:00","gmt_modified":"2026-04-24T11:02:17.62207+08:00"},{"id":1540,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"3ab144009e705151f69698d2d8a81cea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#35-37","gmt_create":"2026-04-24T11:02:17.622971+08:00","gmt_modified":"2026-04-24T11:02:17.622972+08:00"},{"id":1541,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"3ab144009e705151f69698d2d8a81cea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-37","gmt_create":"2026-04-24T11:02:17.623434+08:00","gmt_modified":"2026-04-24T11:02:17.623434+08:00"},{"id":1542,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"570a917d85850ab1208fce5823b110a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#60-62","gmt_create":"2026-04-24T11:02:17.62436+08:00","gmt_modified":"2026-04-24T11:02:17.62436+08:00"},{"id":1543,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"570a917d85850ab1208fce5823b110a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 60-62","gmt_create":"2026-04-24T11:02:17.624694+08:00","gmt_modified":"2026-04-24T11:02:17.624694+08:00"},{"id":1544,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f92c0c41197c488f04f994bf0f7ea465","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#87-104","gmt_create":"2026-04-24T11:02:17.625099+08:00","gmt_modified":"2026-04-24T11:02:17.625099+08:00"},{"id":1545,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"f92c0c41197c488f04f994bf0f7ea465","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 87-104","gmt_create":"2026-04-24T11:02:17.625385+08:00","gmt_modified":"2026-04-24T11:02:17.625385+08:00"},{"id":1546,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5688471e2418628ac2a6409451708d06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-115","gmt_create":"2026-04-24T11:02:17.626962+08:00","gmt_modified":"2026-04-24T11:02:17.626962+08:00"},{"id":1547,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"5688471e2418628ac2a6409451708d06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-115","gmt_create":"2026-04-24T11:02:17.627296+08:00","gmt_modified":"2026-04-24T11:02:17.627296+08:00"},{"id":1548,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-04-24T11:02:17.62778+08:00","gmt_modified":"2026-04-24T11:02:17.62778+08:00"},{"id":1549,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-175","gmt_create":"2026-04-24T11:02:17.628417+08:00","gmt_modified":"2026-04-24T11:02:17.628417+08:00"},{"id":1550,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-24T11:02:17.629023+08:00","gmt_modified":"2026-04-24T11:02:17.629023+08:00"},{"id":1551,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-24T11:02:17.629535+08:00","gmt_modified":"2026-04-24T11:02:17.629535+08:00"},{"id":1552,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-24T11:02:17.630073+08:00","gmt_modified":"2026-04-24T11:02:17.630073+08:00"},{"id":1553,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-104","gmt_create":"2026-04-24T11:02:17.632419+08:00","gmt_modified":"2026-04-24T11:02:17.632419+08:00"},{"id":1554,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"7075cde1c771c46dbbd37b3c09dac53d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#20-41","gmt_create":"2026-04-24T11:02:17.633252+08:00","gmt_modified":"2026-04-24T11:02:17.633252+08:00"},{"id":1555,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"7075cde1c771c46dbbd37b3c09dac53d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-41","gmt_create":"2026-04-24T11:02:17.636427+08:00","gmt_modified":"2026-04-24T11:02:17.636427+08:00"},{"id":1556,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"607e99e751640281d26516c772548b93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#17-39","gmt_create":"2026-04-24T11:02:17.637267+08:00","gmt_modified":"2026-04-24T11:02:17.637267+08:00"},{"id":1557,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"607e99e751640281d26516c772548b93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-39","gmt_create":"2026-04-24T11:02:17.637632+08:00","gmt_modified":"2026-04-24T11:02:17.637632+08:00"},{"id":1558,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T11:02:30.039416+08:00","gmt_modified":"2026-04-24T11:02:30.039416+08:00"},{"id":1559,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-24T11:02:30.039811+08:00","gmt_modified":"2026-04-24T11:02:30.039811+08:00"},{"id":1560,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-24T11:02:30.040216+08:00","gmt_modified":"2026-04-24T11:02:30.040216+08:00"},{"id":1561,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-24T11:02:30.040578+08:00","gmt_modified":"2026-04-24T11:02:30.040578+08:00"},{"id":1562,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-04-24T11:02:30.040879+08:00","gmt_modified":"2026-04-24T11:02:30.040879+08:00"},{"id":1563,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5386144bf3c668c6fa14481c0d85a214","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/subscriptions.py","gmt_create":"2026-04-24T11:02:30.041164+08:00","gmt_modified":"2026-04-24T11:02:30.041164+08:00"},{"id":1564,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f26740f2a1532b38c816663a4f665dbf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/admin.py","gmt_create":"2026-04-24T11:02:30.04145+08:00","gmt_modified":"2026-04-24T11:02:30.04145+08:00"},{"id":1565,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-24T11:02:30.041739+08:00","gmt_modified":"2026-04-24T11:02:30.041739+08:00"},{"id":1566,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5883a8ef4fc156d76b71ffdb5ecdf232","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/rate_limit.py","gmt_create":"2026-04-24T11:02:30.042071+08:00","gmt_modified":"2026-04-24T11:02:30.042071+08:00"},{"id":1567,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-24T11:02:30.042401+08:00","gmt_modified":"2026-04-24T11:02:30.042401+08:00"},{"id":1568,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-04-24T11:02:30.042688+08:00","gmt_modified":"2026-04-24T11:02:30.042688+08:00"},{"id":1569,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-24T11:02:30.042971+08:00","gmt_modified":"2026-04-24T11:02:30.042971+08:00"},{"id":1570,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5013cbe89f1c6f03533eb218400cedb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/subscription.py","gmt_create":"2026-04-24T11:02:30.043264+08:00","gmt_modified":"2026-04-24T11:02:30.043264+08:00"},{"id":1571,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-24T11:02:30.043594+08:00","gmt_modified":"2026-04-24T11:02:30.043594+08:00"},{"id":1572,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-24T11:02:30.043956+08:00","gmt_modified":"2026-04-24T11:02:30.043956+08:00"},{"id":1573,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-24T11:02:30.044289+08:00","gmt_modified":"2026-04-24T11:02:30.044289+08:00"},{"id":1574,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b250fc6c32106a7f3e0c3ad152dfc097","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/subscription.py","gmt_create":"2026-04-24T11:02:30.044599+08:00","gmt_modified":"2026-04-24T11:02:30.044599+08:00"},{"id":1575,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3809c5ab912511e0e093ba02a4fc918f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/admin.py","gmt_create":"2026-04-24T11:02:30.045053+08:00","gmt_modified":"2026-04-24T11:02:30.045053+08:00"},{"id":1576,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T11:02:30.045401+08:00","gmt_modified":"2026-04-24T11:02:30.045401+08:00"},{"id":1577,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-24T11:02:30.045812+08:00","gmt_modified":"2026-04-24T11:02:30.045813+08:00"},{"id":1578,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-24T11:02:30.046255+08:00","gmt_modified":"2026-04-24T11:02:30.046255+08:00"},{"id":1579,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-24T11:02:30.046821+08:00","gmt_modified":"2026-04-24T11:02:30.046821+08:00"},{"id":1580,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-24T11:02:30.047179+08:00","gmt_modified":"2026-04-24T11:02:30.047179+08:00"},{"id":1581,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-04-24T11:02:30.04757+08:00","gmt_modified":"2026-04-24T11:02:30.04757+08:00"},{"id":1582,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#12-78","gmt_create":"2026-04-24T11:02:30.048059+08:00","gmt_modified":"2026-04-24T11:02:30.048059+08:00"},{"id":1583,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-78","gmt_create":"2026-04-24T11:02:30.048441+08:00","gmt_modified":"2026-04-24T11:02:30.048441+08:00"},{"id":1584,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"10d3948b1394ffa0110796edfa0bfc25","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#30","gmt_create":"2026-04-24T11:02:30.049701+08:00","gmt_modified":"2026-04-24T11:02:30.049701+08:00"},{"id":1585,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"10d3948b1394ffa0110796edfa0bfc25","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30","gmt_create":"2026-04-24T11:02:30.050019+08:00","gmt_modified":"2026-04-24T11:02:30.050019+08:00"},{"id":1586,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"fa1ee5e3822128a37e9d03af74083392","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#12","gmt_create":"2026-04-24T11:02:30.050437+08:00","gmt_modified":"2026-04-24T11:02:30.050437+08:00"},{"id":1587,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7e908f05baccdfcf7f4a3ef3c9cd5c38","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#21","gmt_create":"2026-04-24T11:02:30.050938+08:00","gmt_modified":"2026-04-24T11:02:30.050938+08:00"},{"id":1588,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3c41910bad9855635d1362efc314463a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#15","gmt_create":"2026-04-24T11:02:30.051502+08:00","gmt_modified":"2026-04-24T11:02:30.051502+08:00"},{"id":1589,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"3c41910bad9855635d1362efc314463a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15","gmt_create":"2026-04-24T11:02:30.051832+08:00","gmt_modified":"2026-04-24T11:02:30.051832+08:00"},{"id":1590,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f32e078c985967af30d2c526290d9acb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#23","gmt_create":"2026-04-24T11:02:30.052221+08:00","gmt_modified":"2026-04-24T11:02:30.052221+08:00"},{"id":1591,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"f32e078c985967af30d2c526290d9acb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23","gmt_create":"2026-04-24T11:02:30.052506+08:00","gmt_modified":"2026-04-24T11:02:30.052506+08:00"},{"id":1592,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c10a89cdd47474f51664a239b82cc2e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#17","gmt_create":"2026-04-24T11:02:30.052951+08:00","gmt_modified":"2026-04-24T11:02:30.052951+08:00"},{"id":1593,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"c10a89cdd47474f51664a239b82cc2e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17","gmt_create":"2026-04-24T11:02:30.05328+08:00","gmt_modified":"2026-04-24T11:02:30.05328+08:00"},{"id":1594,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-84","gmt_create":"2026-04-24T11:02:30.053738+08:00","gmt_modified":"2026-04-24T11:02:30.053738+08:00"},{"id":1595,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"d6ebce8c7d9e9de127486400670ebed0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#39-84","gmt_create":"2026-04-24T11:02:30.054219+08:00","gmt_modified":"2026-04-24T11:02:30.054219+08:00"},{"id":1596,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"d6ebce8c7d9e9de127486400670ebed0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-84","gmt_create":"2026-04-24T11:02:30.054595+08:00","gmt_modified":"2026-04-24T11:02:30.054595+08:00"},{"id":1597,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-115","gmt_create":"2026-04-24T11:02:30.055201+08:00","gmt_modified":"2026-04-24T11:02:30.055201+08:00"},{"id":1598,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ec3ed02cad3cd8af4bacb5c978273092","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#26-77","gmt_create":"2026-04-24T11:02:30.055878+08:00","gmt_modified":"2026-04-24T11:02:30.055878+08:00"},{"id":1599,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"ec3ed02cad3cd8af4bacb5c978273092","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-77","gmt_create":"2026-04-24T11:02:30.056273+08:00","gmt_modified":"2026-04-24T11:02:30.056273+08:00"},{"id":1600,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-108","gmt_create":"2026-04-24T11:02:30.056757+08:00","gmt_modified":"2026-04-24T11:02:30.056757+08:00"},{"id":1601,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#10-83","gmt_create":"2026-04-24T11:02:30.057383+08:00","gmt_modified":"2026-04-24T11:02:30.057383+08:00"},{"id":1602,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"2db9940a42c91fc92f23595491ea93d1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#67-78","gmt_create":"2026-04-24T11:02:30.057883+08:00","gmt_modified":"2026-04-24T11:02:30.057883+08:00"},{"id":1603,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"2db9940a42c91fc92f23595491ea93d1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-78","gmt_create":"2026-04-24T11:02:30.058168+08:00","gmt_modified":"2026-04-24T11:02:30.058168+08:00"},{"id":1604,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"bcdf50f6234651cb9863ab210e6473e5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-42","gmt_create":"2026-04-24T11:02:30.058557+08:00","gmt_modified":"2026-04-24T11:02:30.058557+08:00"},{"id":1605,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6df0277c2486b148fa26c2682dbdaa4c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-68","gmt_create":"2026-04-24T11:02:30.05912+08:00","gmt_modified":"2026-04-24T11:02:30.05912+08:00"},{"id":1606,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5ea5f192d580031ffe57e1582b70c67e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-123","gmt_create":"2026-04-24T11:02:30.05967+08:00","gmt_modified":"2026-04-24T11:02:30.059671+08:00"},{"id":1607,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"fe4a793f16cd4e12b56253c0a6d53ae0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#24-359","gmt_create":"2026-04-24T11:02:30.060346+08:00","gmt_modified":"2026-04-24T11:02:30.060346+08:00"},{"id":1608,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"68fbb2bd365f96a98ea187a9738c4460","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-57","gmt_create":"2026-04-24T11:02:30.060876+08:00","gmt_modified":"2026-04-24T11:02:30.060876+08:00"},{"id":1609,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"68fbb2bd365f96a98ea187a9738c4460","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-57","gmt_create":"2026-04-24T11:02:30.061204+08:00","gmt_modified":"2026-04-24T11:02:30.061204+08:00"},{"id":1610,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#7-34","gmt_create":"2026-04-24T11:02:30.063434+08:00","gmt_modified":"2026-04-24T11:02:30.063434+08:00"},{"id":1611,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-24T11:02:30.064469+08:00","gmt_modified":"2026-04-24T11:02:30.064469+08:00"},{"id":1612,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ae9de874df4a46f4197b6c157c25ec6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-85","gmt_create":"2026-04-24T11:02:30.065051+08:00","gmt_modified":"2026-04-24T11:02:30.065052+08:00"},{"id":1613,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-04-24T11:02:30.065708+08:00","gmt_modified":"2026-04-24T11:02:30.065708+08:00"},{"id":1614,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-04-24T11:02:30.066709+08:00","gmt_modified":"2026-04-24T11:02:30.066709+08:00"},{"id":1615,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b0777c7da17be89abb333c81c0dcf349","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-261","gmt_create":"2026-04-24T11:02:30.067247+08:00","gmt_modified":"2026-04-24T11:02:30.067247+08:00"},{"id":1616,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-77","gmt_create":"2026-04-24T11:02:30.067743+08:00","gmt_modified":"2026-04-24T11:02:30.067743+08:00"},{"id":1617,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-50","gmt_create":"2026-04-24T11:02:30.06828+08:00","gmt_modified":"2026-04-24T11:02:30.06828+08:00"},{"id":1618,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"44f9c9f195e096efbd6c6a6f97880944","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#51-75","gmt_create":"2026-04-24T11:02:30.069039+08:00","gmt_modified":"2026-04-24T11:02:30.069039+08:00"},{"id":1619,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"44f9c9f195e096efbd6c6a6f97880944","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-75","gmt_create":"2026-04-24T11:02:30.069323+08:00","gmt_modified":"2026-04-24T11:02:30.069323+08:00"},{"id":1620,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"cbe8ffc1cfb98ac79c7659e968191837","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#343-466","gmt_create":"2026-04-24T11:02:30.069788+08:00","gmt_modified":"2026-04-24T11:02:30.069788+08:00"},{"id":1621,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"cbe8ffc1cfb98ac79c7659e968191837","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 343-466","gmt_create":"2026-04-24T11:02:30.070073+08:00","gmt_modified":"2026-04-24T11:02:30.070073+08:00"},{"id":1622,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#18-75","gmt_create":"2026-04-24T11:02:30.070531+08:00","gmt_modified":"2026-04-24T11:02:30.070531+08:00"},{"id":1623,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"97f9b6149bd43feb0f69cf2582ab6305","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#85-117","gmt_create":"2026-04-24T11:02:30.071432+08:00","gmt_modified":"2026-04-24T11:02:30.071432+08:00"},{"id":1624,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"97f9b6149bd43feb0f69cf2582ab6305","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 85-117","gmt_create":"2026-04-24T11:02:30.071724+08:00","gmt_modified":"2026-04-24T11:02:30.071724+08:00"},{"id":1625,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ce4de96353f8f81ca825173ddbec1150","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/subscription.py#12-41","gmt_create":"2026-04-24T11:02:30.072433+08:00","gmt_modified":"2026-04-24T11:02:30.072433+08:00"},{"id":1626,"source_id":"5013cbe89f1c6f03533eb218400cedb0","target_id":"ce4de96353f8f81ca825173ddbec1150","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-41","gmt_create":"2026-04-24T11:02:30.072769+08:00","gmt_modified":"2026-04-24T11:02:30.072769+08:00"},{"id":1627,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a87a1a7c1723518159d5818c197996cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#56-155","gmt_create":"2026-04-24T11:02:30.073186+08:00","gmt_modified":"2026-04-24T11:02:30.073186+08:00"},{"id":1628,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"a87a1a7c1723518159d5818c197996cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-155","gmt_create":"2026-04-24T11:02:30.073474+08:00","gmt_modified":"2026-04-24T11:02:30.073474+08:00"},{"id":1629,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-45","gmt_create":"2026-04-24T11:02:30.073878+08:00","gmt_modified":"2026-04-24T11:02:30.073878+08:00"},{"id":1630,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-45","gmt_create":"2026-04-24T11:02:30.074211+08:00","gmt_modified":"2026-04-24T11:02:30.074211+08:00"},{"id":1631,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f7314a4515e822cba6f37d7a8f1970f3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-46","gmt_create":"2026-04-24T11:02:30.074677+08:00","gmt_modified":"2026-04-24T11:02:30.074677+08:00"},{"id":1632,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"f7314a4515e822cba6f37d7a8f1970f3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-46","gmt_create":"2026-04-24T11:02:30.074964+08:00","gmt_modified":"2026-04-24T11:02:30.074964+08:00"},{"id":1633,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-188","gmt_create":"2026-04-24T11:02:30.075667+08:00","gmt_modified":"2026-04-24T11:02:30.075667+08:00"},{"id":1634,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ef31f4aa4fbd1b6ff76eba467b757a04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#34-69","gmt_create":"2026-04-24T11:02:30.076225+08:00","gmt_modified":"2026-04-24T11:02:30.076225+08:00"},{"id":1635,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"ef31f4aa4fbd1b6ff76eba467b757a04","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-69","gmt_create":"2026-04-24T11:02:30.076612+08:00","gmt_modified":"2026-04-24T11:02:30.076612+08:00"},{"id":1636,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-04-24T11:02:30.077351+08:00","gmt_modified":"2026-04-24T11:02:30.077351+08:00"},{"id":1637,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-24T11:02:30.077878+08:00","gmt_modified":"2026-04-24T11:02:30.077878+08:00"},{"id":1638,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-24T11:02:30.078464+08:00","gmt_modified":"2026-04-24T11:02:30.078464+08:00"},{"id":1639,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-24T11:02:30.079686+08:00","gmt_modified":"2026-04-24T11:02:30.079686+08:00"},{"id":1640,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-04-24T11:02:30.080405+08:00","gmt_modified":"2026-04-24T11:02:30.080405+08:00"},{"id":1641,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"1a2657244414b5681afded9565a86422","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#35-40","gmt_create":"2026-04-24T11:02:30.081664+08:00","gmt_modified":"2026-04-24T11:02:30.081664+08:00"},{"id":1642,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#43-48","gmt_create":"2026-04-24T11:02:30.082422+08:00","gmt_modified":"2026-04-24T11:02:30.082422+08:00"},{"id":1643,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"27a5e2dd1d197b2e3a45be41c57a6183","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#35","gmt_create":"2026-04-24T11:02:30.083022+08:00","gmt_modified":"2026-04-24T11:02:30.083022+08:00"},{"id":1644,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c43e8fc0c04c5ed2db7798d99c8c77b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#34","gmt_create":"2026-04-24T11:02:30.083614+08:00","gmt_modified":"2026-04-24T11:02:30.083614+08:00"},{"id":1645,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3a7201f4564dbcf35c5771f1b5d58cb6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#46-50","gmt_create":"2026-04-24T11:02:30.084198+08:00","gmt_modified":"2026-04-24T11:02:30.084198+08:00"},{"id":1646,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"3a7201f4564dbcf35c5771f1b5d58cb6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 46-50","gmt_create":"2026-04-24T11:02:30.084522+08:00","gmt_modified":"2026-04-24T11:02:30.084522+08:00"},{"id":1647,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a50f983ec39bac67dff5df80f6dad837","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#59-60","gmt_create":"2026-04-24T11:02:30.084964+08:00","gmt_modified":"2026-04-24T11:02:30.084964+08:00"},{"id":1648,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#67-71","gmt_create":"2026-04-24T11:02:30.085559+08:00","gmt_modified":"2026-04-24T11:02:30.085559+08:00"},{"id":1649,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"39c3dbe67ab2ae74446fe6a118bd8738","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#25-29","gmt_create":"2026-04-24T11:02:30.086053+08:00","gmt_modified":"2026-04-24T11:02:30.086053+08:00"},{"id":1650,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"39c3dbe67ab2ae74446fe6a118bd8738","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-29","gmt_create":"2026-04-24T11:02:30.086409+08:00","gmt_modified":"2026-04-24T11:02:30.08641+08:00"},{"id":1651,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"68d937267aab2509edc0c7b67e1b5ef6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#53-57","gmt_create":"2026-04-24T11:02:30.086938+08:00","gmt_modified":"2026-04-24T11:02:30.086938+08:00"},{"id":1652,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"68d937267aab2509edc0c7b67e1b5ef6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-57","gmt_create":"2026-04-24T11:02:30.087245+08:00","gmt_modified":"2026-04-24T11:02:30.087245+08:00"},{"id":1653,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#22-25","gmt_create":"2026-04-24T11:02:30.087665+08:00","gmt_modified":"2026-04-24T11:02:30.087665+08:00"},{"id":1654,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-25","gmt_create":"2026-04-24T11:02:30.08803+08:00","gmt_modified":"2026-04-24T11:02:30.08803+08:00"},{"id":1655,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a9c1b0716ae36af22fce6148c2e40ce5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#47-49","gmt_create":"2026-04-24T11:02:30.088435+08:00","gmt_modified":"2026-04-24T11:02:30.088435+08:00"},{"id":1656,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"a9c1b0716ae36af22fce6148c2e40ce5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-49","gmt_create":"2026-04-24T11:02:30.088761+08:00","gmt_modified":"2026-04-24T11:02:30.088762+08:00"},{"id":1657,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"2793782c-91c8-4052-b9db-39513426c736","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 2793782c-91c8-4052-b9db-39513426c736","gmt_create":"2026-04-24T11:08:43.063241+08:00","gmt_modified":"2026-04-24T11:08:43.063241+08:00"},{"id":1658,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"e23bd86e-b4ac-40eb-b1c1-38d929fd5419","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e e23bd86e-b4ac-40eb-b1c1-38d929fd5419","gmt_create":"2026-04-24T11:08:43.063978+08:00","gmt_modified":"2026-04-24T11:08:43.063978+08:00"},{"id":1659,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"70b3948e-f456-42d2-b7ad-a0097ad5ee5f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 70b3948e-f456-42d2-b7ad-a0097ad5ee5f","gmt_create":"2026-04-24T11:08:43.064613+08:00","gmt_modified":"2026-04-24T11:08:43.064613+08:00"},{"id":1660,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","gmt_create":"2026-04-24T11:08:43.065266+08:00","gmt_modified":"2026-04-24T11:08:43.065266+08:00"},{"id":1661,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"7e679d62-c415-4d6a-a7e5-d41d00e0ed69","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 7e679d62-c415-4d6a-a7e5-d41d00e0ed69","gmt_create":"2026-04-24T11:08:43.065797+08:00","gmt_modified":"2026-04-24T11:08:43.065797+08:00"},{"id":1662,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","gmt_create":"2026-04-24T11:08:43.066252+08:00","gmt_modified":"2026-04-24T11:08:43.066252+08:00"},{"id":1663,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"df661133-efbf-43fe-97c3-f581c81f47a7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e df661133-efbf-43fe-97c3-f581c81f47a7","gmt_create":"2026-04-24T11:08:43.066859+08:00","gmt_modified":"2026-04-24T11:08:43.06686+08:00"},{"id":1664,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"11936bb5-374f-40f4-bb53-b75264fc4b9d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 11936bb5-374f-40f4-bb53-b75264fc4b9d","gmt_create":"2026-04-24T11:08:43.06741+08:00","gmt_modified":"2026-04-24T11:08:43.06741+08:00"},{"id":1665,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"23ad3419-5473-4e2c-ac87-d9715090279d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 23ad3419-5473-4e2c-ac87-d9715090279d","gmt_create":"2026-04-24T11:08:43.067912+08:00","gmt_modified":"2026-04-24T11:08:43.067912+08:00"},{"id":1666,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"19e75845-5147-4aeb-90be-16f3aa270465","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 19e75845-5147-4aeb-90be-16f3aa270465","gmt_create":"2026-04-24T11:08:43.068381+08:00","gmt_modified":"2026-04-24T11:08:43.068382+08:00"},{"id":1667,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"83fe6837-7874-4467-8114-103062f15f58","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 83fe6837-7874-4467-8114-103062f15f58","gmt_create":"2026-04-24T11:08:43.068809+08:00","gmt_modified":"2026-04-24T11:08:43.068809+08:00"},{"id":1668,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","gmt_create":"2026-04-24T11:08:43.069423+08:00","gmt_modified":"2026-04-24T11:08:43.069423+08:00"},{"id":1669,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"2b32ec11-d228-42c0-9232-103ba7e44f71","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 2b32ec11-d228-42c0-9232-103ba7e44f71","gmt_create":"2026-04-24T11:08:43.070039+08:00","gmt_modified":"2026-04-24T11:08:43.07004+08:00"},{"id":1670,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e ba0390b3-c249-4e92-a3c8-6820343aeda9","gmt_create":"2026-04-24T11:08:43.070549+08:00","gmt_modified":"2026-04-24T11:08:43.070549+08:00"},{"id":1671,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 760610d4-dff6-4c6d-831f-7c9078db86a6","gmt_create":"2026-04-24T11:08:43.071132+08:00","gmt_modified":"2026-04-24T11:08:43.071132+08:00"},{"id":1672,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a40267bc-925a-4364-a01f-b96d3df60aea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e a40267bc-925a-4364-a01f-b96d3df60aea","gmt_create":"2026-04-24T11:08:43.07161+08:00","gmt_modified":"2026-04-24T11:08:43.07161+08:00"},{"id":1673,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"7bd2c461-81b0-48e8-8cb3-b4b14305806d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 7bd2c461-81b0-48e8-8cb3-b4b14305806d","gmt_create":"2026-04-24T11:08:43.072138+08:00","gmt_modified":"2026-04-24T11:08:43.072138+08:00"},{"id":1674,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d5c75004-b01b-416f-850a-4791c5489a32","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e d5c75004-b01b-416f-850a-4791c5489a32","gmt_create":"2026-04-24T11:08:43.072666+08:00","gmt_modified":"2026-04-24T11:08:43.072666+08:00"},{"id":1675,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","gmt_create":"2026-04-24T11:08:43.073112+08:00","gmt_modified":"2026-04-24T11:08:43.073112+08:00"},{"id":1676,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e 262a3941-fdc6-46b0-b767-be40aa9d5761","gmt_create":"2026-04-24T11:08:43.073598+08:00","gmt_modified":"2026-04-24T11:08:43.073599+08:00"},{"id":1677,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7c0201f7-9e02-4cba-9ee1-81c3477f049a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e 7c0201f7-9e02-4cba-9ee1-81c3477f049a","gmt_create":"2026-04-24T11:08:43.074022+08:00","gmt_modified":"2026-04-24T11:08:43.074022+08:00"},{"id":1678,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7c7564ee-7fe2-4555-8ff0-4ec1b757997a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 7c7564ee-7fe2-4555-8ff0-4ec1b757997a","gmt_create":"2026-04-24T11:08:43.076175+08:00","gmt_modified":"2026-04-24T11:08:43.076176+08:00"},{"id":1679,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 74d3018f-4e23-4687-8bf4-7fb403f479f7","gmt_create":"2026-04-24T11:08:43.07673+08:00","gmt_modified":"2026-04-24T11:08:43.07673+08:00"},{"id":1680,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"737f8d6c-bd8f-4c11-b142-71a400423323","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 737f8d6c-bd8f-4c11-b142-71a400423323","gmt_create":"2026-04-24T11:08:43.077384+08:00","gmt_modified":"2026-04-24T11:08:43.077384+08:00"},{"id":1681,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ae62f4a8-8840-4c8e-9a42-3373370299ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e ae62f4a8-8840-4c8e-9a42-3373370299ff","gmt_create":"2026-04-24T11:08:43.078078+08:00","gmt_modified":"2026-04-24T11:08:43.078078+08:00"},{"id":1682,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"ec2f1708-d31e-42bb-8959-fa405db7d6da","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e ec2f1708-d31e-42bb-8959-fa405db7d6da","gmt_create":"2026-04-24T11:08:43.086144+08:00","gmt_modified":"2026-04-24T11:08:43.086144+08:00"},{"id":1683,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2059d1cd-98a3-4b7f-b29b-69acf8a0d751","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e 2059d1cd-98a3-4b7f-b29b-69acf8a0d751","gmt_create":"2026-04-24T11:08:43.0867+08:00","gmt_modified":"2026-04-24T11:08:43.0867+08:00"},{"id":1684,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d474a7a6-e056-4456-ba79-4aedbb7add58","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e d474a7a6-e056-4456-ba79-4aedbb7add58","gmt_create":"2026-04-24T11:08:43.087214+08:00","gmt_modified":"2026-04-24T11:08:43.087214+08:00"},{"id":1685,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2d7c030d-7b82-418c-9a16-67b067cac93c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e 2d7c030d-7b82-418c-9a16-67b067cac93c","gmt_create":"2026-04-24T11:08:43.087792+08:00","gmt_modified":"2026-04-24T11:08:43.087792+08:00"}],"source_files":[{"id":"12e2c3d7b9a92dc44a6ee29b85e10df6","path":"frontend/app/layout.tsx","filename":"layout.tsx","gmt_create":"2026-04-23T15:19:43.754128+08:00","gmt_modified":"2026-04-23T15:19:43.754129+08:00"},{"id":"2a1c745c7b3fb7f600596be3d979bba1","path":"frontend/app/(dashboard","filename":"(dashboard","gmt_create":"2026-04-23T15:19:43.756075+08:00","gmt_modified":"2026-04-23T15:19:43.756075+08:00"},{"id":"eca13a610badfc5ffc6210827fb96991","path":"frontend/components/layout/header.tsx","filename":"header.tsx","gmt_create":"2026-04-23T15:19:43.756308+08:00","gmt_modified":"2026-04-23T15:19:43.756308+08:00"},{"id":"18a0651d895fba9bb4e0c0229459efdc","path":"frontend/components/layout/sidebar.tsx","filename":"sidebar.tsx","gmt_create":"2026-04-23T15:19:43.756496+08:00","gmt_modified":"2026-04-23T15:19:43.756496+08:00"},{"id":"5d7886d0dc99f81073a578b8aefdd375","path":"frontend/lib/api.ts","filename":"api.ts","gmt_create":"2026-04-23T15:19:43.756648+08:00","gmt_modified":"2026-04-23T15:19:43.756648+08:00"},{"id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","path":"frontend/components/ui/table.tsx","filename":"table.tsx","gmt_create":"2026-04-23T15:19:43.758184+08:00","gmt_modified":"2026-04-23T15:19:43.758184+08:00"},{"id":"108b0c4b4dcfb6aa39a5eb138225c148","path":"frontend/components/ui/dialog.tsx","filename":"dialog.tsx","gmt_create":"2026-04-23T15:19:43.75905+08:00","gmt_modified":"2026-04-23T15:19:43.75905+08:00"},{"id":"ef72f0c3cedb9fd9a87352fe493053dc","path":"frontend/lib/platforms.ts","filename":"platforms.ts","gmt_create":"2026-04-23T15:19:43.759223+08:00","gmt_modified":"2026-04-23T15:19:43.759223+08:00"},{"id":"f93ae024fe0a2e69698037dff6df205f","path":"frontend/lib/utils.ts","filename":"utils.ts","gmt_create":"2026-04-23T15:19:43.759351+08:00","gmt_modified":"2026-04-23T15:19:43.759351+08:00"},{"id":"d5f2266643d2011c66e86af088ec637f","path":"frontend/components/charts/trend-chart.tsx","filename":"trend-chart.tsx","gmt_create":"2026-04-23T15:19:43.759489+08:00","gmt_modified":"2026-04-23T15:19:43.759489+08:00"},{"id":"f1a7d61831cc0a45ac6220294f15c21d","path":"frontend/components/charts/platform-chart.tsx","filename":"platform-chart.tsx","gmt_create":"2026-04-23T15:19:43.759606+08:00","gmt_modified":"2026-04-23T15:19:43.759606+08:00"},{"id":"9228ff67d4c757a85d9421b71f4b29f5","path":"backend/app/main.py","filename":"main.py","gmt_create":"2026-04-23T15:19:45.5873+08:00","gmt_modified":"2026-04-23T15:19:45.5873+08:00"},{"id":"93022c8938ce318f167277cfa65c29a7","path":"backend/app/api/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.587785+08:00","gmt_modified":"2026-04-23T15:19:45.587786+08:00"},{"id":"6b3d903205941aa9391dd90016e1102c","path":"backend/app/api/queries.py","filename":"queries.py","gmt_create":"2026-04-23T15:19:45.588167+08:00","gmt_modified":"2026-04-23T15:19:45.588167+08:00"},{"id":"7538ffe4902ab6041adb28b19844962a","path":"backend/app/api/citations.py","filename":"citations.py","gmt_create":"2026-04-23T15:19:45.588473+08:00","gmt_modified":"2026-04-23T15:19:45.588473+08:00"},{"id":"58901c94d975d87e652a4dc6c8dda656","path":"backend/app/api/reports.py","filename":"reports.py","gmt_create":"2026-04-23T15:19:45.588695+08:00","gmt_modified":"2026-04-23T15:19:45.588695+08:00"},{"id":"9d08667997a868fc07c9b4e328e44224","path":"backend/app/api/deps.py","filename":"deps.py","gmt_create":"2026-04-23T15:19:45.588857+08:00","gmt_modified":"2026-04-23T15:19:45.588857+08:00"},{"id":"e0c0ca66b8b81cf66e078a7ab162c07f","path":"backend/app/schemas/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.589011+08:00","gmt_modified":"2026-04-23T15:19:45.589011+08:00"},{"id":"f301b79d833233ce39d350e82a71c938","path":"backend/app/schemas/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.589202+08:00","gmt_modified":"2026-04-23T15:19:45.589202+08:00"},{"id":"1a3336b4af8a39a055e912724338580c","path":"backend/app/schemas/citation.py","filename":"citation.py","gmt_create":"2026-04-23T15:19:45.589399+08:00","gmt_modified":"2026-04-23T15:19:45.589399+08:00"},{"id":"4d2f3847b7c10634733118b70a1aea0b","path":"backend/app/services/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.589591+08:00","gmt_modified":"2026-04-23T15:19:45.589591+08:00"},{"id":"88d22de3b2a7419868e8ae19130d860c","path":"backend/app/services/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.589732+08:00","gmt_modified":"2026-04-23T15:19:45.589732+08:00"},{"id":"04e3926c080e795713bff683e7dc9d3e","path":"backend/app/services/citation.py","filename":"citation.py","gmt_create":"2026-04-23T15:19:45.589852+08:00","gmt_modified":"2026-04-23T15:19:45.589852+08:00"},{"id":"9ff19022ef915615911280e3c49ed44b","path":"backend/app/config.py","filename":"config.py","gmt_create":"2026-04-23T15:19:45.589987+08:00","gmt_modified":"2026-04-23T15:19:45.589987+08:00"},{"id":"c59f8c276697a070dffc581fe94d809c","path":"backend/app/models/user.py","filename":"user.py","gmt_create":"2026-04-23T15:19:45.590197+08:00","gmt_modified":"2026-04-23T15:19:45.590198+08:00"},{"id":"b74caccb06844efcdb14d8324cff65c2","path":"backend/app/models/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.590343+08:00","gmt_modified":"2026-04-23T15:19:45.590344+08:00"},{"id":"b4a81ef789630d0af6a8d50859d01bf3","path":"backend/app/models/citation_record.py","filename":"citation_record.py","gmt_create":"2026-04-23T15:19:45.590489+08:00","gmt_modified":"2026-04-23T15:19:45.590489+08:00"},{"id":"069738f21ac2da7349d22683e8c36929","path":"backend/app/models/query_task.py","filename":"query_task.py","gmt_create":"2026-04-23T15:19:45.59062+08:00","gmt_modified":"2026-04-23T15:19:45.59062+08:00"},{"id":"5cbb1e3f112aeba62a14b0b8999fc0f5","path":"backend/app/workers/scheduler.py","filename":"scheduler.py","gmt_create":"2026-04-23T15:20:08.953491+08:00","gmt_modified":"2026-04-23T15:20:08.953491+08:00"},{"id":"74040de652d5e57f548bb5c4adc3e1a0","path":"backend/app/workers/citation_engine.py","filename":"citation_engine.py","gmt_create":"2026-04-23T15:20:08.953836+08:00","gmt_modified":"2026-04-23T15:20:08.953837+08:00"},{"id":"8f973791233c698b3e64a4fb28a93d4b","path":"backend/app/workers/platforms/kimi.py","filename":"kimi.py","gmt_create":"2026-04-23T15:20:08.954103+08:00","gmt_modified":"2026-04-23T15:20:08.954103+08:00"},{"id":"f642fc1c2f34e15572d9d98aa6c18813","path":"backend/app/workers/platforms/wenxin.py","filename":"wenxin.py","gmt_create":"2026-04-23T15:20:08.954273+08:00","gmt_modified":"2026-04-23T15:20:08.954273+08:00"},{"id":"a16cf42e9559523c4f96ca4c79f9488d","path":"backend/app/workers/platforms/base.py","filename":"base.py","gmt_create":"2026-04-23T15:20:08.954406+08:00","gmt_modified":"2026-04-23T15:20:08.954406+08:00"},{"id":"b0c428683c8a3e6922d90ca0d8c2736d","path":"backend/app/database.py","filename":"database.py","gmt_create":"2026-04-23T15:20:08.955702+08:00","gmt_modified":"2026-04-23T15:20:08.955702+08:00"},{"id":"b2f0d46a31a5441594f2e777365fc156","path":"tests/test_scheduler.py","filename":"test_scheduler.py","gmt_create":"2026-04-23T15:20:08.95621+08:00","gmt_modified":"2026-04-23T15:20:08.95621+08:00"},{"id":"0613e76b9679be7f998fb8fd8056e686","path":"tests/test_queries.py","filename":"test_queries.py","gmt_create":"2026-04-23T15:20:08.956336+08:00","gmt_modified":"2026-04-23T15:20:08.956336+08:00"},{"id":"99fe1b288fd41daa86c2dfbab819abf0","path":"backend/app/models/__init__.py","filename":"__init__.py","gmt_create":"2026-04-23T15:21:46.682639+08:00","gmt_modified":"2026-04-23T15:21:46.682639+08:00"},{"id":"bceca00463fe55d3bcafda728f97f723","path":"backend/app/models/subscription.py","filename":"subscription.py","gmt_create":"2026-04-23T15:21:46.684259+08:00","gmt_modified":"2026-04-23T15:21:46.684259+08:00"},{"id":"d4f95fcf50683b5bf6167c7d2a6b126d","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","filename":"488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-23T15:21:46.684619+08:00","gmt_modified":"2026-04-23T15:21:46.684619+08:00"},{"id":"0ef1efea889dba3e1f299626df479571","path":"tests/conftest.py","filename":"conftest.py","gmt_create":"2026-04-23T15:22:15.981194+08:00","gmt_modified":"2026-04-23T15:22:15.981194+08:00"},{"id":"389d631bc6c7111ba411b0b79fca455e","path":"tests/test_auth.py","filename":"test_auth.py","gmt_create":"2026-04-23T15:22:15.98141+08:00","gmt_modified":"2026-04-23T15:22:15.98141+08:00"},{"id":"80a0429cc47931de27ddb17a62b8dd9c","path":"tests/test_business_flow.py","filename":"test_business_flow.py","gmt_create":"2026-04-23T15:22:15.981566+08:00","gmt_modified":"2026-04-23T15:22:15.981567+08:00"},{"id":"b07a4fb9cecbbd66a6910ccbc7651f19","path":"tests/test_citation_engine.py","filename":"test_citation_engine.py","gmt_create":"2026-04-23T15:22:15.981715+08:00","gmt_modified":"2026-04-23T15:22:15.981715+08:00"},{"id":"42ff5383133d176cec9eb88682483be3","path":"tests/test_citations.py","filename":"test_citations.py","gmt_create":"2026-04-23T15:22:15.981831+08:00","gmt_modified":"2026-04-23T15:22:15.981831+08:00"},{"id":"aaf5bce6be82d2f947bfa5c1806de452","path":"frontend/package.json","filename":"package.json","gmt_create":"2026-04-23T15:22:23.492837+08:00","gmt_modified":"2026-04-23T15:22:23.492837+08:00"},{"id":"01056dad8851d3e9bd532eb4cab33792","path":"frontend/tailwind.config.ts","filename":"tailwind.config.ts","gmt_create":"2026-04-23T15:22:23.495792+08:00","gmt_modified":"2026-04-23T15:22:23.495792+08:00"},{"id":"ac1acbc54c49ee1de13369f6c6827568","path":"frontend/components/ui/button.tsx","filename":"button.tsx","gmt_create":"2026-04-23T15:22:23.496353+08:00","gmt_modified":"2026-04-23T15:22:23.496353+08:00"},{"id":"0186dc8a89340139a84e1e3c5571a57f","path":"frontend/components/ui/dropdown-menu.tsx","filename":"dropdown-menu.tsx","gmt_create":"2026-04-23T15:22:23.496869+08:00","gmt_modified":"2026-04-23T15:22:23.496869+08:00"},{"id":"3cf787fa77a15b2b1783560c6d83ed21","path":"frontend/components/ui/input.tsx","filename":"input.tsx","gmt_create":"2026-04-23T15:22:23.497127+08:00","gmt_modified":"2026-04-23T15:22:23.497128+08:00"},{"id":"3c56e1c079959bfcc985183805e5874f","path":"frontend/components/ui/select.tsx","filename":"select.tsx","gmt_create":"2026-04-23T15:22:23.497457+08:00","gmt_modified":"2026-04-23T15:22:23.497457+08:00"},{"id":"0d5ef537f7c0b8c390f8b31d7cf47b56","path":"frontend/components/ui/card.tsx","filename":"card.tsx","gmt_create":"2026-04-23T15:22:23.497745+08:00","gmt_modified":"2026-04-23T15:22:23.497745+08:00"},{"id":"51821ca9ec2a1c972f3c9d111e19db8a","path":"frontend/components/ui/badge.tsx","filename":"badge.tsx","gmt_create":"2026-04-23T15:22:23.498034+08:00","gmt_modified":"2026-04-23T15:22:23.498034+08:00"},{"id":"beb87ab5aad9532647e9dbd2db7ef587","path":"frontend/components/ui/tabs.tsx","filename":"tabs.tsx","gmt_create":"2026-04-23T15:22:23.498711+08:00","gmt_modified":"2026-04-23T15:22:23.498711+08:00"},{"id":"792b8e2c16c9ff2095d83b8972313be4","path":"frontend/components/ui/label.tsx","filename":"label.tsx","gmt_create":"2026-04-23T15:22:23.499031+08:00","gmt_modified":"2026-04-23T15:22:23.499031+08:00"},{"id":"546e01c5f73aaf5140eee922f4b9a441","path":"frontend/components/providers.tsx","filename":"providers.tsx","gmt_create":"2026-04-23T15:22:23.499298+08:00","gmt_modified":"2026-04-23T15:22:23.499298+08:00"},{"id":"e68ad5186f1e47610ab3d9f14a794393","path":"backend/app/workers/platforms/tongyi.py","filename":"tongyi.py","gmt_create":"2026-04-23T20:31:36.476814+08:00","gmt_modified":"2026-04-23T20:31:36.476814+08:00"},{"id":"404f6d0765a8c6e77e33b7fc21b377a4","path":"backend/app/workers/platforms/doubao.py","filename":"doubao.py","gmt_create":"2026-04-23T20:31:36.477414+08:00","gmt_modified":"2026-04-23T20:31:36.477414+08:00"},{"id":"303e80519e946904d1cb3ac32cbb0814","path":"backend/app/workers/platforms/qingyan.py","filename":"qingyan.py","gmt_create":"2026-04-23T20:31:36.477731+08:00","gmt_modified":"2026-04-23T20:31:36.477731+08:00"},{"id":"5af7301fe056fc3d10820d820e8ad777","path":"backend/app/workers/platforms/tiangong.py","filename":"tiangong.py","gmt_create":"2026-04-23T20:31:36.477969+08:00","gmt_modified":"2026-04-23T20:31:36.477969+08:00"},{"id":"0e38ad5d2d3daaad08c9302df8805b15","path":"backend/app/workers/platforms/xinghuo.py","filename":"xinghuo.py","gmt_create":"2026-04-23T20:31:36.47825+08:00","gmt_modified":"2026-04-23T20:31:36.47825+08:00"},{"id":"6a63f048c16c60c5d2d57012c810ee0e","path":"backend/app/workers/platforms/search_engine.py","filename":"search_engine.py","gmt_create":"2026-04-23T20:31:36.478564+08:00","gmt_modified":"2026-04-23T20:31:36.478564+08:00"},{"id":"a26ee01cf41da3b956e1650448c156fa","path":"backend/requirements.txt","filename":"requirements.txt","gmt_create":"2026-04-23T20:31:36.48051+08:00","gmt_modified":"2026-04-23T20:31:36.48051+08:00"},{"id":"e9b52adbec3c07cf021e488dd3f99ab4","path":"backend/Dockerfile","filename":"Dockerfile","gmt_create":"2026-04-23T20:31:50.452043+08:00","gmt_modified":"2026-04-23T20:31:50.452043+08:00"},{"id":"4a56ef5fca60bc63480b457cab3832f0","path":"backend/app/workers/platforms/__init__.py","filename":"__init__.py","gmt_create":"2026-04-23T20:35:18.583102+08:00","gmt_modified":"2026-04-23T20:35:18.583102+08:00"},{"id":"36dd0ad3ee6bc75a480ad8a62268e80e","path":"backend/app/workers/models/query.py","filename":"query.py","gmt_create":"2026-04-23T20:35:18.58383+08:00","gmt_modified":"2026-04-23T20:35:18.58383+08:00"},{"id":"a680d4819f5da57fe9fa0e6bc708f380","path":"backend/alembic/env.py","filename":"env.py","gmt_create":"2026-04-23T20:35:45.568869+08:00","gmt_modified":"2026-04-23T20:35:45.56887+08:00"},{"id":"f6e6948dd0cdd3894bd9928b21feb979","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","filename":"b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","gmt_create":"2026-04-23T20:35:45.569946+08:00","gmt_modified":"2026-04-23T20:35:45.569946+08:00"},{"id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","path":"backend/alembic.ini","filename":"alembic.ini","gmt_create":"2026-04-23T20:35:45.570621+08:00","gmt_modified":"2026-04-23T20:35:45.570621+08:00"},{"id":"fc6242433ae9506bcc0bf4cb0dce1413","path":"docker-compose.yml","filename":"docker-compose.yml","gmt_create":"2026-04-23T20:35:45.574312+08:00","gmt_modified":"2026-04-23T20:35:45.574314+08:00"},{"id":"5e414f2ef9b69e55e00ab15f85b9291a","path":"frontend/Dockerfile","filename":"Dockerfile","gmt_create":"2026-04-23T21:00:59.630269+08:00","gmt_modified":"2026-04-23T21:00:59.630269+08:00"},{"id":"fb8af100a06778e1fbdac4790a3ed0a9","path":"frontend/tsconfig.json","filename":"tsconfig.json","gmt_create":"2026-04-23T21:00:59.630887+08:00","gmt_modified":"2026-04-23T21:00:59.630888+08:00"},{"id":"4d9b59c294a0aac5e300b3de715eb226","path":"frontend/.eslintrc.json","filename":".eslintrc.json","gmt_create":"2026-04-23T21:00:59.631396+08:00","gmt_modified":"2026-04-23T21:00:59.631396+08:00"},{"id":"48a560c49d2b21da327c036ec2934b96","path":"README.md","filename":"README.md","gmt_create":"2026-04-23T21:00:59.633061+08:00","gmt_modified":"2026-04-23T21:00:59.633061+08:00"},{"id":"ed630a36e81abafd12787d4095dfe8c2","path":"backend/README.md","filename":"README.md","gmt_create":"2026-04-24T10:58:35.330288+08:00","gmt_modified":"2026-04-24T10:58:35.330289+08:00"},{"id":"1cafc02d1d722feb4692dab6ae85c09f","path":"frontend/README.md","filename":"README.md","gmt_create":"2026-04-24T10:58:35.331593+08:00","gmt_modified":"2026-04-24T10:58:35.331593+08:00"},{"id":"d2c1984414de6856ed5b3873c661b712","path":"frontend/lib/auth.ts","filename":"auth.ts","gmt_create":"2026-04-24T10:58:35.334476+08:00","gmt_modified":"2026-04-24T10:58:35.334477+08:00"},{"id":"f26740f2a1532b38c816663a4f665dbf","path":"backend/app/api/admin.py","filename":"admin.py","gmt_create":"2026-04-24T10:58:51.055493+08:00","gmt_modified":"2026-04-24T10:58:51.055493+08:00"},{"id":"5386144bf3c668c6fa14481c0d85a214","path":"backend/app/api/subscriptions.py","filename":"subscriptions.py","gmt_create":"2026-04-24T10:58:51.055792+08:00","gmt_modified":"2026-04-24T10:58:51.055792+08:00"},{"id":"b44632a0f399b2fe2b4daf295a120ec7","path":"backend/app/middleware/logging_middleware.py","filename":"logging_middleware.py","gmt_create":"2026-04-24T10:58:51.05617+08:00","gmt_modified":"2026-04-24T10:58:51.056171+08:00"},{"id":"5883a8ef4fc156d76b71ffdb5ecdf232","path":"backend/app/middleware/rate_limit.py","filename":"rate_limit.py","gmt_create":"2026-04-24T10:58:51.056416+08:00","gmt_modified":"2026-04-24T10:58:51.056416+08:00"},{"id":"5013cbe89f1c6f03533eb218400cedb0","path":"backend/app/schemas/subscription.py","filename":"subscription.py","gmt_create":"2026-04-24T10:58:51.056765+08:00","gmt_modified":"2026-04-24T10:58:51.056765+08:00"},{"id":"3809c5ab912511e0e093ba02a4fc918f","path":"backend/app/services/admin.py","filename":"admin.py","gmt_create":"2026-04-24T10:58:51.058083+08:00","gmt_modified":"2026-04-24T10:58:51.058083+08:00"},{"id":"b250fc6c32106a7f3e0c3ad152dfc097","path":"backend/app/services/subscription.py","filename":"subscription.py","gmt_create":"2026-04-24T10:58:51.058233+08:00","gmt_modified":"2026-04-24T10:58:51.058233+08:00"},{"id":"b0cb6810919f64006be7aa66b2b76a61","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","filename":"c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-04-24T10:59:38.893705+08:00","gmt_modified":"2026-04-24T10:59:38.893705+08:00"},{"id":"955e1dfe57f0a9a8e900383eb7641ba1","path":"frontend/next.config.mjs","filename":"next.config.mjs","gmt_create":"2026-04-24T11:01:58.061252+08:00","gmt_modified":"2026-04-24T11:01:58.061252+08:00"},{"id":"5800a08224424ebced854d06365f6d44","path":"frontend/app/(auth","filename":"(auth","gmt_create":"2026-04-24T11:01:58.062019+08:00","gmt_modified":"2026-04-24T11:01:58.062019+08:00"},{"id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","path":"frontend/types/next-auth.d.ts","filename":"next-auth.d.ts","gmt_create":"2026-04-24T11:01:58.062472+08:00","gmt_modified":"2026-04-24T11:01:58.062472+08:00"},{"id":"facea1f00ec72e00f774d0839fee7131","path":"#wiki#main#wiki#zh/[app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","filename":"route.ts)","gmt_create":"2026-04-24T11:01:58.064844+08:00","gmt_modified":"2026-04-24T11:01:58.064845+08:00"},{"id":"37d7291b1373216dcf08f081a94ab1c8","path":"#wiki#main#wiki#zh/[frontend/app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","filename":"route.ts)","gmt_create":"2026-04-24T11:02:17.54199+08:00","gmt_modified":"2026-04-24T11:02:17.54199+08:00"}],"wiki_catalogs":[{"id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"项目概述","description":"project-overview","prompt":"为GEO项目创建全面的项目概述内容。详细介绍GEO平台的核心目标、主要功能特性和技术架构。解释项目作为智能学术查询与引用管理系统的设计理念,包括多AI平台集成、定时查询任务调度、数据可视化展示等核心功能。说明前后端技术栈的选择原因和整体架构设计思路。提供项目背景、应用场景和价值主张。包含系统边界、核心组件关系图和数据流向说明。面向初学者提供概念性理解,同时为经验丰富的开发者提供技术决策的背景信息。","progress_status":"completed","dependent_files":"backend/README.md,frontend/README.md,backend/app/main.py,backend/app/config.py,docker-compose.yml,README.md","gmt_create":"2026-04-22T18:56:47.080895+08:00","gmt_modified":"2026-04-24T10:58:35.431076+08:00","raw_data":"WikiEncrypted:nzQO5jvliy8ncyK0FT40s3j/+jLrEduTcrc/mlxpgSLdYjBwtNztvkbMoPPMFNEMDes7QSOWotr7g4sRG3hN1QC5esoYS3BvN6Y/T/6GOvnwo5Ww+L13yRESwkAhTxZ0bDtqMqBMDJjp0MKl68qbq7B2U5OjVB5vyO1G7qlX+bY4a+E+zpn1E17PQvN9P7VlQgVDqa1nwz8U0c4YkUjlvSLoRXqMUPWbTTo8enr8varFiB9kZhlIveqWyQg70c2so+mmgK5tu58aGpglpVdjphh9cbkx8+rqqdDcytUZT7S8pKc4MGkZe3rCbq6nyT0QAyu8WwZ0h9/zER3M3mecpY0QwlpWFcQiEekYeGeusO+eNSbtIN9Tohtik8zfV/pV0TaGc/LbnkcMtj8m0T83c8wKIfYs/liR225bzfnhLIqsoF6rOnXNLIoTpE8Z6Ks8+5swWOqw0Oa1WUgNMnH79HbG7z2uBctEg3Kb/3wmXweL49APkVOhhX9rJu18yc8nR26giaoFIlCpKme7nOHGBbxVcV8/JH1uRvSJLspnk9+gwQcK6n07+/KN5SIq/dFPZUVljWill5+4lQiNxtX+bZcGsWdNjyiate8dGLZoiydoxbt8zaaOQ/sE/vzpNhUqORGkQ8zSh8rLkJEdzSYUCb95gUWs+6vCBogO7GSPqHQcoYZi5WnndLvZiktMpSEJFxGL8OBQQmyD6Z6bOiznhTf01DdqjQOJBP1sIfkt1trL9OQOr20Ak7fnYetRoaFaSlNhpQQ/hgidyWqYv/uEjDqbh6r8sMdfkOJfWVQwoTFcSfwD2/Ezujp/A0M27lE6NNRroam4tql49iIRkSJ8j5Mqpc4aSg/1LGSCtGFO7lgwS9gOqERvjimyvLJqWq3dZ0cOYXDKpKLA0X7nDR9XyX2YWJS4KaXUr5+S2sxJzO7sAlTKSz6PH6BQ/b2JlcDCx+56VN8QMP+RCcbydnghzXKe6RgzxbAnDpW0JuxjjZ4MX8K34hI8qs2i0yxuU9+Mf/FjPgDApnz61m6zpE7ytZaS5gDZPTG3wIPktdrLMdemyyufsG9Lw++TxZ0idt/BkMk5EUrehRV+xT+AOX78k10N+lSt8JqDE3IeHtwqfFd0is91jzyBsgYPlipjXY6xSsJlNTYZ8aU/1mQMFLZvcMTTF703Kx6yRYTe1s9QIB3LdfeaNqDov7ouvZRgU5fNwWTcIt9sUTJn5/2mwjZpBmntggvmpmp5wC7dpNB6kBNb8jJrmRLMepO0ocqPbXE6JhTb8/yOhegEy3fJ1RNTeTZIEpBt4+sCZtc5TA3aJSYPZ51wEGmqMbiVCl1DnxLKmBc0O0JH97VCXcyhIKj4aOGsfQbqM3cyeIWuRNds3/do3Z8vOc9AQfcOnwFZU1H3df4iLKZ9pDyMVGCNqEeKew=="},{"id":"7c3e3c0b-5d1f-4d64-99be-668041c6cd9d","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"核心框架配置","description":"core-framework","prompt":"为GEO后端核心框架创建详细的配置文档。深入解释FastAPI应用实例的初始化过程,包括应用名称、版本管理和生命周期管理。详细说明CORS中间件配置、路由注册机制和健康检查端点。文档化配置管理系统的实现,包括环境变量读取、配置验证和默认值设置。解释数据库连接池配置、异步会话管理和连接超时设置。包含应用启动和关闭流程的详细说明,以及资源清理机制。提供配置最佳实践和常见问题解决方案。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,backend/app/database.py","gmt_create":"2026-04-22T18:57:02.316945+08:00","gmt_modified":"2026-04-22T19:03:21.69307+08:00","raw_data":"WikiEncrypted:luoNp8LvFa7zGThvIT9T4rhp6COPRJpm3tT/kftARqFq4dg1cG/8M10NcCrCelp/LC8SV6McSk0Sx9xEgJV/YmEmjfMmlukALh9v7ZKLxT8XDDYkBCrff2Ia9KfGFRdlfVmmQUGfhQARTeykGZh6O8/4GECBHUYLS0F6NXI7fSS3R+/I5c/HIjI7F17mVNpZDQZcc2HmM4zhdyIinOGyErSf3vIPcfVVobPB4D/wCUvMWxl+jpvktykHTIgH9ze7f4fTCC02xK5vRnt1RlMdAQ3d1Km7OOGjAga30OGvRdp9UtT48gdhzPQH5FEbfzn7K6TnuPzqQRf4GuS2kVTRSUFbSnmj5d5HqHmgx7D9iQYR/XxRRVbv+GeFwINvVa+UX9cnanYU19zazOGWG2rcdDk8jqu5MwAhVZsT28hykyuLfKeTf7xuM6Li86T1mZ18SROCJHe4LXYEaH94K6CHjZLCyEl10xBk02/CkW4aTW29TIgrponrmnrvV6bShQ+ZitR1TcivPsNN5t6TCaHMnlaLlOpznSGNpMyf4S51cRPxl2cwZrqJbrdFxehIoPrUyOvtRvtEsLhpo30456ihrInvbVXgJMwZIcDaKHSu0Bf7ma8y+UCWH61+VBIqW44KzA9zmKcXU9hiiwL+gjwiNcV7JDcgg43Un4qvjEzeJiBRBMGGzc8Oc05dWgRs1K6QUdS1kZTjI/JKiGS8zFYKz0mvQqLwc6/xe1/MDhMyU1QUXSqpcNNU6aFmY7te5kENN2aSPZqigqID+RwvIV8k8JETdmHaxJUzCSrNEpbpUukFuVQKz419athf4kMeQH2fKsLMZABn10WnnmY9HGGqBx+gpNOTU9AiSz1l4b0Ej8XoQcwIn1lqw49qdJ6+PRuuFBv6OcjxgJSMNSQzm4c/eyl7yv6J4vXceT7Ul+ySMAGRnSpDUehmOuw1DT4dV0n05Rcrx5gBjuztOAexxUhLwMUK/v+8qdn/0OcciISCZ/U1GhzhWFYiVKRBfNuNkuRjwmc4zg5Zc97TPRBXYs2q2e0/3cT+Dr7lqeGnXWL3X4iTjTygXMekhDQBjc0NbF6cdDOJcPAUnOg6jDkreBiEkTJ7hZg3J9ho2RYDaHuPvyMlkW4YWTpGRODtXIs4aLG0KFbNr6uOG31hOPZsgnHmoNwcPwRUO4G89Nkl2M6ZTMiNHWtsSwES+gLmCLPunm7R2zQNtdei+K3lzSg0bQgUvg==","layer_level":1},{"id":"bcaa04da-04e3-427f-ba01-847ad657e78a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Next.js应用配置","description":"nextjs-app-config","prompt":"创建Next.js 14应用配置的详细文档。说明App Router的页面组织结构,包括路由规则、嵌套路由和页面布局设计。文档化全局样式配置、字体系统和主题定制。解释Tailwind CSS的配置选项、自定义样式和响应式设计原则。说明TypeScript配置、类型定义和开发工具设置。包含性能优化配置、构建优化和生产环境部署设置。提供配置最佳实践和常见问题解决方案。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","progress_status":"completed","dependent_files":"frontend/app/layout.tsx,frontend/app/globals.css,frontend/next.config.mjs,frontend/tailwind.config.ts,frontend/tsconfig.json","gmt_create":"2026-04-22T18:57:04.216045+08:00","gmt_modified":"2026-04-22T19:04:47.361369+08:00","raw_data":"WikiEncrypted:MoQ9U2rERvJfHcC2U9f5yo5PrhAUeAY0OH9kgPk99cOGQSyTenUDM+krr5XcMxqj+FSA7CYnuq8hz8eS8Pvzc8yZuRRHbRPExvPpdrOEr8fRtUXkjnECv8NVvFPloo2fonxY9Q2vmL0x2O1UsV1O6L6tkraG28x1o504hsBitow5XMWkk8uSk+sDbyHo/y9/SBDWpcEOXVqeU4nwD/UU+7N90n5i5T89nz6b4M+31tkvffIuZRigZ+1+IJqlsqFgRt9PNrxL9ZUsD2D/Yvh8EJ0sCr9z7AI+D3z+JYM2kgFT/3ugS/EnEzwByGZk/e2EsOY4D+NkRBas836JX++o61ZH5GPQBXTHnVa8h5B1LAVlbA5zBuJHHY3V2XS4X1cTo9Hj76mg9Ha+jWvX2A9fv4vnscE6cVxnM+WjWnSfN8N7Vtla2YRDrNXZRAL50+PNfhUKpb48d0hKFyzf1Av1T4WBKgaYEo2znphEy99ViuG+oOFS6D5pVQ/w5yoPe5MpZCDk4aNsO/owrJkILcGc3+qHfld4Yd4HtYM6madWmmOvHIIuCy5CPGojBzKDcTTSPP6ZjuY1EC/RG3lBkYCQtQj889+80GZpaSbrqWjTmMI1DX1KLNXJkoI3dFk5Tx+w4TqiKICJ8q9KJhOX+mEVk+ECXqrc2Qz787D34zY5UlwsaA44ziBvWDZuwfPWmtelAq4KjqfWTFWYqdY6D0fUvetLh3/VEqH/o5Nh4HrlGvy/faZbU9FKOBZPkAy8c0J24rW5p2pKmRq6+2IicNTgufRROtiY87GKfbfmqpDYBEn3Dogv/Q3i5beVavuD1tJWhRsewhAZAUi1jWdiK3LyS0QI7dMFXVJw3cm2FnegeXA8CNlWnjUVSOY/OfLFqJJqYrfcj57f3nAU4a88w4h10+iFBLh0yZkX50llRxgUjV0fnjyEFUDoinC1xDA9ip9IOosTI+avZPhLTC0Yn4ZGnJi4NCD5cD88+KIdRUnVZJ5Sqf4ZcCCQamtYBT8NJ+PlByYxpqJpGtLyV9BuexYC86YnD3PJau0oXazcytuXMYh/TTaEo89ZzW4jpsqDM1G/gBUq7R+QDzLElNZfw3Ov0E0+Pvfm89W+v2iSsJ2JI2Yq7wrml7FiTN0KoP5KVEBCEzDLwebnJFqa7GBaghwADYcgoZ2VX2Xtin82a3oqlX2WNfur2DIr4YURiSmE8g8O","layer_level":1},{"id":"9e3d703f-f424-47f4-84df-b99873b93e5a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"项目介绍","description":"project-introduction","prompt":"为GEO项目创建详细的项目介绍内容。解释GEO平台作为智能学术查询与引用管理系统的核心使命和价值主张。详细描述项目解决的实际问题,包括传统学术研究中品牌引用检测的痛点、多平台数据整合的需求等。说明项目的目标用户群体和应用场景,如研究人员、市场分析师、品牌监测团队等。介绍项目的发展历程、设计理念和创新点。提供系统的功能概览,包括智能引用检测、多AI平台集成、定时查询调度等核心能力。面向初学者解释项目的基本概念和使用价值,为后续技术文档奠定基础。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,README.md","gmt_create":"2026-04-22T18:57:13.329466+08:00","gmt_modified":"2026-04-22T19:05:00.376007+08:00","raw_data":"WikiEncrypted:0MI1/XkBoMl0lTbK6t0CnyIiRc/FeBluVaO5vMjpi7GJDj6RYPJBK8z3pvJGG/q2Umz028dfdXdKirGdHRY2lrn0erk9nv1ZHCzuughhzuFHwcxdCPIpZdrZtQpPh6bsxkWiwYzSScq7WGo0sBeTvyoiisiPXNkFNbSjUGQOu0M9zOwZAcknYWqtf16nUcOV3lRfAFHfNSt77Nc0IUQGl1zM4BWFjitEsa6cq/jjGIh7XC2gcTvm2eWRaWDDr5n6IcJZtD0ODJYzhH9IJVk4uIXlKksbQcuIrmEWEkZBxeh+DAIp0tmgXr52zuL9uRxapFuSlOq3BlU5N3I+Iu8Fg/rBAnNcvKEwSk/71gIbFlwaxLvik5gposBrfcD4U1+MJLRTPhgg/HJwljnpTC13NERk70aJg2/SCvFZcO+86xWuLwvNjWRxc2K8yOeJggfWG6S/Dt0dGaFl5F44u6XDbQV0GKiDfNOzo5CtzO7CrkSRJ+zErGQOEEoF6UhVmmpA6ONf2YDr/z3Z5bIP5z605qNZZWUDPVLjU5elINOMi4fsEw3OYaerNp6aoSHA1eXnOJoJIMsU0KM3eGAO9QNhHE2PlkwXulCEX5l1tkohbwthcv94cBVsn64CtaMMgjrgUkflNYnfEM1djmP2iJFEG/MjNMntZCrVRGXdjjqR4Q+lRe3ELhXuHjqeU5RS+KdYLASsYBDzti2T8foSfBxxXcpMIz/lS8+Qx3pTLW3ktH5AaEtSdclWCF2HLc1/03O/gdv070KOck/8TXbyZsJ6g3fzThY7xASttVsW1IITTaX9XE52YkNOe7KOrjJwkSbUgOU1Rv3Aa7x3VJ/ac9nDL4AgS+TlYNxfYBlGkbesL+sqDgWrL268y38MyK0DRqEQVjCxV9+7aAkxLvaUXVMYIwxqAM9Id66zRb0pJB3uwgpOAIRzOCskNEghjp17p4BK3lgehkRcM9RAGb7WqgeNfl/+ox2b25Pj+nvbWN3XghNZwNzoTW+kBZxXhOTRvIyAne7IPRpmtD1XD6ZBx/C6ucQ7kTUL/7LqFXE66g3Zey3hiaiQihueSMCFVer6F+BIMSBpV+9cmAczdqYvXRnKIjQg15zwVGz7mKE4D7caiDjkAQeMUSqziw+i/S26Ont/JBHIsLpYISQJErTAl2rGwC+7ADw+H6jg0rn+nE5s5u9fxUPMsWodcWi5oGIFRRTyGeIZYSTNveEwN8h0LGwXhUlHR6RxBAIpbiwKVUcOFOKc7mojhJEN36mXsQdRyCUjV3YdNzj2Tw5tG4exPzStsjDxSn98XK42QisGde126iI=","layer_level":1},{"id":"a06436ee-1678-4a51-bbf8-b0d0ac3456b9","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库架构","description":"database-architecture","prompt":"创建GEO项目数据库架构文档。详细说明基于PostgreSQL的异步数据库连接配置,包括SQLAlchemy异步引擎设置、连接池管理和会话生命周期。文档化数据库连接字符串配置、环境变量管理和安全考虑。解释异步数据库操作的优势、性能特点和最佳实践。包含数据库连接监控、错误处理和故障恢复机制。提供生产环境配置建议和性能调优指南。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","progress_status":"completed","dependent_files":"backend/app/database.py,backend/app/config.py,backend/alembic.ini","gmt_create":"2026-04-22T18:57:14.160162+08:00","gmt_modified":"2026-04-22T19:05:13.623934+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkJxdCaPVm76qYvPs0DmFrBYr++cWSoBpsZCop64XjnmZv6vHv8URIJAqohtlaw1HFotKc3mK0aD3tk5jmFWmTjGEd9iSTEcB45Yccg7p5eggZzqexWRLP1afxRQPau2t5uy1dZIlExyu+lyiNQI9/hXf1UppgfCjo4u6akBIZtYhzgcUSoYY4jCjv0naBAT/PyevZQctOpKPIBwMdeB86h71UT0hKB1hXxbyQoljBYZmATJaRjmlQzZf/Ka1gnDj1s1WVsGMpSoA7jyNRPH+Ra6hR+5N8Ba5vkjxM/HcRFq282Jnr/TnidF4MF5HpD5Piye73QZ3zAvIbu8+iOSvpQee/FTzkrUQBy0xOA5lsfFOy5OFOKtQh0mHybuNqe6H5squ2Tge+K4+RKXbDCt0wptrSV+BVQ+OkAJJEtLNRpJElsQ5bw1UU6CuzbgnnEYrMXB5TMBI5N2/J6hmlqt978t04N3zVI9JnnFKK0H2og6TVu1Hrxq/xEB8RFWTf/WNN1p4Akee5r1uOuUry6hsO2yQUTlmHq74QnJz4o4YJodWkhwAmcyzPIlMeSFg/Kr/EvsQJN4UprhudCTvNitnPaBesVkucYDYQiVAhxyNSAqCzZUYXbyuLD4r5DKxKzvHjkhRugm73yBM7wzbxB2lABMiGM9p90FASIxS0SfzIl4qrFbO/oQGRIFaYfUCnQF8h0YDi40UX4/LVmnlT/L8y/d+hU00P5j5PI0qOyoRDqsfQZFaze+qtibkMnJ//iy0Awl0wqQ47SxaB0jhTc07lPFBLSHFSoVUaKDs1DPGiwKjpWZRzAw7rbv9NFuV+irKc0l8qDNCaK6Rk0rRd0ukFuszcaE9n92URbvv0Fk8XTHLr8sFAh/xMm63r5hUAuqEYN6z/Si5Isq52UmJ1/TvnLYIUK58JHTuDsVn3MKJ2fTgUw/U3g+N61WpDIgGvaHO75crgWZbS9qQyDoSSj4wNdxWR+wtmKjwZdRK44kWRBS1QebMTLNYDBgHD5hPnmOa5W/Rx4Y0QBw6UFjCy/GOmDI=","layer_level":1},{"id":"7fea5a24-e6de-4003-bc70-9dae6d8fdb25","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"适配器架构设计","description":"adapter-architecture","prompt":"创建适配器架构设计的详细文档。详细解释BasePlatformAdapter抽象基类的设计理念和实现细节,包括平台名称、平台URL等核心属性的定义。说明抽象方法query()的设计目的和参数规范,以及close()方法的资源清理机制。文档化适配器模式在AI平台集成中的应用价值,包括如何通过统一接口实现不同平台的无缝切换。提供适配器扩展的最佳实践和代码示例,帮助开发者理解如何为新平台创建适配器。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py","gmt_create":"2026-04-22T18:57:14.592407+08:00","gmt_modified":"2026-04-22T19:06:14.01609+08:00","raw_data":"WikiEncrypted:mEeeU1uNqYKn4jkG2zPtuGBVTFJMKL8+aALSFPkyoEYifQL2Z+klmgmPGyzF3YlP0xw/C/hG8jzgXcVjqaWbA8lOQYPPvd4qFK8fszqAYs/fYEHXvWBVaOTbFhjNiT5k+li1MqVRx7SiaRze/N6NV4j39o5dfNAouxnCXgLyBZdG5QXj6JAfhJ1mTHsYQFDmrIU+nOtrQvRh3bruUOURVd64c13kwbBISJKHVwByRrfqWLRTsCLXPYfsgZF4rkL+Iz9x27Nl0VXvNcIIoMXj9B7hg2PPcQlmup4U8y2LhUHmKrdiKpW1t+XZ8rpO2aPKpzr47rn+3n2axWoQIDjWKlHAwi5AhxgPysB/i5EGv0pvgo/mNNIfsZlmSYgXASM6bgCzH5W4O4oJVqOi+gaLuI5+i7N8/+s+FKb63H9ZNvwClw5jXJe2Xm1YUwVGLG8KX5beKRTmBgnyDPmOW17/OXwsWMWQSQKrgpiv+2C7VQqI8X/agBVWawLJAc8VloY281S3ZH5LTa/6ajeGUVXiwpWSD/YWzo9sxLdws1ZXCInzLYy5vX7YflgBOlw+pn6Z901TBktq5jxrG3CFTbRLGxaeG1aJ06sLEFoPzLSXIIiEIuAROC6lPr6XpYAKESgWGOG0GdM3BinxdkriGn21ZZjENIJ436aZjsOiE5M20/kJAnjWIBPEJ/sv3nsi7u5iLfYFvkus4GfnKXJyto9LWiTgqrwHoEUQy4+pnVW+ce//iLlM/t0ZknimuBfzgYSWx/jPc8o9ZU5OIserDAYGaE4sDZIDQas1jOq8HGN/q4wJR7sW7Fw1jKyl4suQZE6QSfYx6molnJ1cSVKcsGrf7AHDKM5x+uGRmLWXqMMUZXXtbbCw0mwqfxAUPiRLUdVyzot8dh/NIWX6B1KABd/kKs+L+vVuCmMen1XVfP72Uy91fYOkBj/xPkA6GYrempnrB6zh6INdvGw5dEKlvNARMnZZLCA64Xw4h2TBjbkIjsBawvJtT+wEGkfkPk5z99jbaaGS65e/JDF/g5WNnKSX0B1Xo+frM1AFwnKR4dIJXZ8=","layer_level":1},{"id":"78288302-33bd-44f7-8b29-24f516c8b6bb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"调度器设计","description":"scheduler-design","prompt":"创建调度器设计的详细文档。解释基于APScheduler的AsyncIOScheduler架构选择和配置,包括调度器初始化、触发器设置和任务注册机制。详细说明调度器的核心组件,包括QueryScheduler类的设计模式、事件循环管理和异步任务包装。文档化调度器的启动和关闭流程,包括资源清理和优雅停机机制。提供调度器配置参数、性能调优选项和扩展方法。包含实际代码示例展示调度器的使用模式和最佳实践。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:25.383156+08:00","gmt_modified":"2026-04-23T20:33:30.132403+08:00","raw_data":"WikiEncrypted:z5m818jdZZHs9QqQTrTafQ5BuN3hUq8ojqzL8SUBUvazzYVUu4EVEqQ8I56QCaxYSTvxoxfSrvjJk5zRU5X7dcnw4Xa3OBhn3OLehoT3E+tyMxhlJSbJpOfp1afGCLyH7k587Ud4I355IvboUvSoBViL1WL1yQq+6Tus1CsKPq1yHjNiWT35OfV9g7bRu5xE+1nSxjPu58jZpFKuN1x9oqF5OJmckHxf5sVFqKlGPU2yyeGdpzKRagbQGUkBdw72yxzSyevTXJ4y+UPCQLh2FLZ8RgYP0OD705z2xIGb7KSeQocLcW5FoxR79ySiibc+AmzE0OBKZqbcm/aw8K5lAK1GP31LdhjrndMTmXrsf9CYBNRIir1QOJsuCh6zPtpsvQVmrX7DpqXiWsaqnK2GVOkKPtnYAJnGsEQhaoX24/64eSYeSnJ7KIsQxP0MHUrRG85VVGF2ADUGh6L8qzexe7uE+lnaqgC8HBQ7CnQ3Ugnj5hcO7vnwQl67NHMOQ5yaL1SpfURVWAx3jjUBU4xjHfmUNcBC2VM6ie9C6Ulelai8Pg0+gFL0A+pfN/Mkzzh05wcgnmFbWfjabZ4Ofv/w+UlG5qhMsEJQAgag4tXHgP/86pheTsfyefYhWEkow983vJf6mYl4lgRaFHeOZ/JBTmM0sxmg1PMZ8wgClMSC0a9SKcsAyWOh0yMuBn/Ckhx4HqGoPAP1rx/k9TkBiHFEoEAXeTNoeg/Wn7tVimdgZvAjW79z7lbcRV1cvlKMSjhRyO2s6n6N3Z6xTlKtLrqHBbXZcrjNQqJVgW91Xk78+a1haDNngswufhJkTJcH8hp3hSUCJeU/Cpx3RYRRf7E3bGmj4sV/+yXAybUvCOhs1s89mYVFThdpDifMbvN5C8a9xrjKJNfjzijlVZwx+cGy5aj+ZQFSDCRCBHvCCIBd76w8uxi+VR8VhbsIryP2KUNpudqIY4V56Jx3DB+dznNJMasPFZZ2ZttlKIAV7oqWrreoweIqeEIugrIM4TdE4EWmokDP5wr0tBdyerPnkaCgJLQj3X2K/xjY6ony3F4svfG1pk2jd5JwTLnudwS4dnGY/1b//vEDGI668cQtR5fW7+APXXb8qjOLlzM4Enze4mw=","layer_level":1},{"id":"b027f234-4ac5-4d6d-9b38-afc8054325f5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"单元测试","description":"unit-testing","prompt":"创建GEO项目单元测试的详细文档。说明各个模块的单元测试实现,包括认证模块测试、引用引擎测试、查询处理测试和引用数据测试的具体用例设计。文档化测试夹具的使用方法,包括mock_user、auth_token、auth_headers等测试辅助对象的创建和配置。详细说明测试断言的编写方法和测试覆盖率要求。提供具体的测试代码示例,展示如何测试异步函数、依赖注入和错误处理。包含测试数据准备和清理的最佳实践。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","progress_status":"completed","dependent_files":"tests/test_auth.py,tests/test_citation_engine.py,tests/test_citations.py,tests/test_queries.py","gmt_create":"2026-04-22T18:57:25.616384+08:00","gmt_modified":"2026-04-22T19:06:55.090058+08:00","raw_data":"WikiEncrypted:oQ7VNoYBl3ApU4O5/TGa/YEO9ObmRNw6knddpSF6M+qfBokxpt9FAn5Oh9wXkjVweu6TpLk0XawcRFRcQ09Zi+YnQyN8+4Ep9fANKzHyAxzcnhkI4VZF35j3DwTbhekUFTKQ+71fms4SP6LGrVw+8IP/eqJC2TH96LJR1oxckQk//yfvKqFHsMLgziXy6zrXuQO8PIu5U/WbkKUkJHWSkLkoTtPteU+WKljSMapCS60e0RUDWZEPuFD2uupr2PJxT8AoOXx358C9XEj8tQ+OwHpsBiR7NdmO0D3GmcgVUcuU7WWxnToWu1UM1d/t4u+x7bIQvHQIDjLWR40nTrvBZJBSSiui0he3T03jLkIB7r9kxCpm9mFUx0fkmUSWp7FRfs7MfJkuoQYVU0YHf6/FF6g/PoQ8ieyqr4YaNjM3kk8GirHkmKjfdQt9YmQtuzMWnzUQ6COtN+BG3STyOvO+12YQAYi5LWe7u7oP4D7TJRReg7FeLDQ60Y8KEoKBJKM051F7pgHlorthWz42brF5tF7oa0tjB4AtWaEwXdCvH278kzwHNEW9E5zeERzX3hlHYL+mKpTbemJlfuHuRugCRy4EKFRP0RYiIUecBK82Pi4Vi9MGjB7cQxIEutHQ/3D0JNLGwEo5TCsk4W3isoF+mJDFy6/IDwgW/+5FIo7V/G18dTg9YbFRwMecdvBfJU5QZV4R993bdx+kH6qB5IoJrA0AzBOCn99YQ/xgAd3w/82Z5vR8syeNZjHYmcx8P/XrYDk4UZTwaacEHfn7tcq+tL5qJDbxdY95wjaWRo9giFE8woDfoLWstvKA1/q+YOyDsIHC/uHjNP1L0ELPZ9ssFuHcwLVrqDwlcblya4+oXlPEOH2ar22uXNRmFyd8Mf8MmEWVZklodBHSKiGUlj8eSWqtR+Cw5Am1gmeUcOxqan5YwzpyXet6g5ll12dnu6ItLby6qm+kjET3rsjaJag7UBlMXWV9xn9Vj4QDK8USPTTWkRUEAj4WH9QqECQzUtYJ6+GsIE7LGx/5tzApMdX3BThIiG8C2k5ry3z310nAMX/pTSrGFGjy8tWFf+KH95sJ6aG4CDyxSPHT/3ivhXAnKDesNYTVgSIKNmAUcj5hRjTfJeGyljB7NEs6Gxz0tf5k+GQLwvRX6PxSnMGkm+q0yx0MNDRBYJNlPCFKUR74ZAU=","layer_level":1},{"id":"940e5918-1689-4001-a284-44f2de75b8ee","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证接口","description":"authentication-api","prompt":"创建认证系统的完整API文档。详细记录用户注册接口(/api/v1/auth/register)的请求参数、响应格式和错误处理。说明用户登录接口(/api/v1/auth/login)的JWT令牌生成机制、认证流程和安全考虑。文档化用户信息接口(/api/v1/auth/me)的权限验证和当前用户获取功能。包含完整的请求示例、响应示例、状态码说明和常见错误处理。提供认证中间件的使用指南和最佳实践。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","progress_status":"completed","dependent_files":"backend/app/api/auth.py,backend/app/schemas/auth.py,backend/app/services/auth.py","gmt_create":"2026-04-22T18:57:37.836287+08:00","gmt_modified":"2026-04-22T19:07:12.356456+08:00","raw_data":"WikiEncrypted:uxAckj1IXK2TQH//kEdeBPmScopsydAsQUjZb8Fs6jI7ezX3WnM5wMv74LMiw55tL2+YKxETbMgwkBQYqIg1VTja5IjBYqljlAzD5l6SrkKU835vZQoOKlYgIFEEXj5PMURu9+2Om7SDVgjbSQ05vLa2aVIBV6PiVswRGc5EGTGtYnV+DJs4BxHzYpH0Ac7KkyHUCGgH6w5QDaOxWt6c5gftFmsRwr8WVKANmqlNU9uhDjmWzjTtSqZ39EVbLd++OjVbpLbTtijQ6gOF0KBBS4B0N5k+Xm2/gDv+HNK9kZ0BphZE1Si3NfV0+cu27HLJ2XV9w357rte4pplU0wYG5oC6cuO7eBFxQdCR6e+ejXIvKGahQOce8d/jWexjfdWnUzvQ18PU4+bUZmiP+YD1dJVBFgxggbCIHG8VFTQBqMaYwc3NLWogjXnczII+Z3sLLneLkVAQEdQ381GeRKdaD4PrtAWp1Ss2QpGHWUKDdaNSLcfm5NXEe6GeECxXH96p6BvyegD3twPfZmY9WKG8YOhXqbpzae/+DXnUTfldYKnMfbonSav0nUBYt8JA0L3oceaNs03211fvlSgE8L9vtUDtNF5lHkhOLMLbu000pe/VWc8WVQRbCKd8KPd4TUxMkB61vQNIcvlRKLMJLNSnE1VftRTpdEpWKhm5qkLfOfikgsp2qp1iSw5Idpu/TLQPIGN/sYpTJ1eACeXt/A3qrlITHFV8by4utTXDT1gRQQ7j7n51fQHHEIbpU+6CRhSBBQfa5IlWAqkarenBmr5RY74jeX7tlhDhvFojQGHYyMaDsZO8G/H93/20YG/li4iihHLIYmsN+2YRP/KWCNaopBGp7tRyZi//RKVXdHGteWxP7vse7URwPhfmHDUB6dMExCT5PwgsYoDwD32k19Eauv4c6OogAMMUN3I9rhSo3V0cde7/xSOhJ34SUY3w9VpPAu1I4zTqhY649YmBnNEjtGLZGTnEJWSdneSPsudvl1HJKg6faq1dMy0dVkMqbHaqMCooFDhiYVS1AM1cG07y9rQisvQP8Ic3NTPAA7BhH0nrPnLc615Jg+XEAjs3brkNXEVZlxNvX5ZqMCoMqsiZrA==","layer_level":1},{"id":"6406f42a-e10b-4a2b-84a5-0a21c1c759ea","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"代码规范","description":"code-standards","prompt":"创建GEO项目的代码规范文档。详细说明Python代码风格指南,包括PEP8标准、命名约定、导入顺序和注释规范。文档化TypeScript/JavaScript代码规范,包括类型定义、接口设计、模块组织和错误处理模式。说明前后端代码风格差异和一致性要求。提供具体的代码示例展示正确和错误的编码方式。包含自动化代码检查工具的配置和使用方法。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","progress_status":"completed","dependent_files":"backend/requirements.txt,frontend/tsconfig.json,frontend/.eslintrc.json,backend/app/__init__.py","gmt_create":"2026-04-22T18:57:39.373374+08:00","gmt_modified":"2026-04-22T19:07:51.274139+08:00","raw_data":"WikiEncrypted:Gw00+yNdsAXvNpUHE0sZ2+QbHW33I6XBnIRt1QjI/FW/5OIgpgiMvU/f+bhXrxoZK5Mgo6YrGuAKhtZ2BPutU1EdQeDFUnQQxxqSupe1WUkFgEECvCkbZOAHimRWBeUutq2qKCfVhu1+US1y8n87OZXUUvVSAksZOa8lbb2AHyiKTMdzzPThS0D+8uOalkBg1mvJCS9fqVoZzY5BYYpuH5eZJBglHbA4uMbdFVTSKVFfHaJ8nlm6uYjaY0sJCSg+dhEAIiMfOTXP5Bh59kxWfLSdZU6b8oPvLV0btsiS22/oEJZI4rWjJ0YTxfQ4jRv348P+GQ6oi1pvwveiJyOxLq8QcVKSiDxO55Ovd76PhOgpOp2WJcUsKoKBoxs817utm+Ld0htpPBS3V90Rw+suMSPCU0mCa80FTrBNn6PnXemH7lH1ozQIu3Y/AGNYBN93acBxtiZ09sGFh2sO9mbbCU0iRuNe9nwWa4MsA5rJMLGdRbyv6jk03+sAvuKwZHXyTWxqeXvMatOUKXzTNfmhXsE+Bexe1vaukG22SWhsXu7FhIaH4Rt7CdpMW0jjbZOf4CwKY36ucVBRwft6ymuED4ihzikPz7pJ5IEuxLGtCyt5QDqT7kbv5ITx4NM/Q2IMMTRZf9bAZyN64PV2TJVCNK11yU+cE7y8HFBNFSzPfDBGFmxijKjTL9MvlElogPp0+qckxGclnip/IOFc6/WAbPNK0qXq98Jq5DsZwLsx4//8yOyRyaQGmOVaOWxb3Aum4RIf933X/hzoTFpV2uSLSznRyCwLpKqjp2zMS7lCj9aDhWLcx5J9NxXfdxFVxBsapMeDDl5xR5nfTFJcOFylsdPxEdxf5J8ULB77F3OmE8Hff/40adNMxJHMyBmju99HNnMZkGLjC68HEPNMZ/6T0+m/Sq1yHOrakYMiw6vnQvmLW4cBIhsTFbhbgpkazGFTk8xsKH3pGySrLXL4xmadfs/g2X/lRrLbSonWaQehTqHYrhz4HIxrTUDn4kdxaPPDhH4fHdEu/69Dri0DSzmSF2m8W3hh1gbAbUO/mbHob1eJg0yKGzyh8AmvUlwXIRGrOwQA5dUZNPSo+oCcv1qlrQ==","layer_level":1},{"id":"e8ec6ac6-ad1a-4332-a7be-727b47d71233","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Docker容器化部署","description":"docker-containerization","prompt":"创建GEO项目Docker容器化部署的详细文档。说明Docker Compose配置文件的结构和各个服务的配置参数,包括数据库(PostgreSQL)、Redis缓存、后端(FastAPI)和前端(Next.js)服务的容器设置。详细解释容器间的依赖关系、网络配置和数据卷挂载。文档化Dockerfile的构建过程,包括多阶段构建策略、依赖安装和运行时配置。提供完整的容器编排流程,从镜像构建到服务启动的完整步骤。包含环境变量配置、健康检查设置和故障排查方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,.env","gmt_create":"2026-04-22T18:57:40.354835+08:00","gmt_modified":"2026-04-22T19:08:34.084609+08:00","raw_data":"WikiEncrypted:h7ADvj4WLJHyulzCl+z7kNgZWY+r5P000yRKX1NQnlv1Xv3Dqgu5Ve8V72HxPVQrbKK8WU/ipQ1PAqV6SDrNgrc1Neea6KoTKr95imYAh3dYgIt/lZ1sndBbQCFqOF87dQsUIEKQgwrsicAeQ0zdudUWh6EW2nyIF0NGa50xffbgEr1mm/MThBZjOua+YnCRogCbgtirEO/6HGlC+I33w/bfFI+rREYKdumqUEia0kUP0pWSpwWjOQp06I7cUoSrx/LuJJ4in5YsZetdjzxdbA3ZvGMjeyI/VVF6UC/QUOgE2csP9z42v6XdOOngM/coBHI3DiUrroBGTPa6BVxJdngItCJ9XcNvXPbo0xMAkAoUKnNPA72B2pRuk4F1sTiOaSCQ1jaMiCTFvbj7+VleaodRFLDFsYa8f1w2FkiW7cEBhFpFgB7Qfru+Yi11rpkjnM2def+Sqq2PSHQ+Ji83jPoQXFl935rDQbNUy28wOIE3BdWN5jjM3nyoXcqKjPVjLf3cxGvg/sbdWk1FYPMIsbK/DUWayyTHt6L/fYkDQYjY5h0H6Q0jBxlhNQ34GG8kEcvrZ6Dy/jtCtE149pi/ToeMbpPq21c5KUhs9OHcEHgMjxWMaEVjQXMjFCpKyJIPfC984tfoZhAHi9WupzyEi37/igcgVJnvIdtadpX7uRxW2JCdfoHn1H87nGQj4eAeI3kMhtJ3EIPd/D6STxUcgtyLdTIZu9kgvnBIN4OyZeI1ygNZfawwQMmbDxHZ1pPcyZDHFlz1HZ0NFX+7VnN2b25TJP2hxMCZ/5OdYeSLozIbM/azA8QMHofESSdxDX9ZDdhvENDlngxUBmxM8+yCAWHENGYqWDL0gZMMDwe89n48Xy9qnKNLX0ROfG4FAtoXsEgLlPQM3AWFETnzr7Kvuma+8sY1iaMVIXJ/MWoy1zLwuY/oOZhVqGLX+DOEupKhk1oQmiqzciCeV8my5Q6LQeriSBww4jA3r6VQMPzBVzKJYz+TLizB6Esf//9+ilsgUVUc6GjD41Ml4fb1GZO3PzxGWrcX1RUE6RKllUBVNffxzE2WCirEX4e4YprntsHu6SAb9TLIInCx7aZnlVnaDQE5BCiHLjIQJnsHHJzlBm+8jtzE4zi7ljHLfbJwhtZ9W6S9KGUqjjNryjTVnVyYQlumOT8HCAkz3fSM6MpXwQr1qz/gHyDrQanmM1O9B/0ox5O2NWcOm5qtsteiyxwKACdyxrsUx0X9BaU8xygDL75XcTfcaOTcICRwaRZF3/UQW+zhbJo9LnHxq30JzTbxU7wEdjpWZQHZ+tu5BMrIqi4=","layer_level":1},{"id":"a91fff3d-ec5e-43df-8176-22f0084109ef","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"功能扩展","description":"feature-extension","prompt":"创建GEO项目功能扩展的详细文档。说明如何新增API接口,包括后端路由添加、数据模型扩展和业务逻辑实现的具体步骤。详细介绍前端页面扩展方法,包括Next.js页面路由添加、组件开发和状态管理集成。文档化引用检测引擎的扩展机制,包括新品牌匹配策略添加和竞争品牌识别算法的实现。提供UI组件库的扩展指南,包括新组件开发、样式定制和响应式设计。包含完整的代码示例和最佳实践建议。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","progress_status":"completed","dependent_files":"backend/app/api/,frontend/app/(dashboard)/,backend/app/workers/citation_engine.py,frontend/components/ui/","gmt_create":"2026-04-22T18:57:48.684421+08:00","gmt_modified":"2026-04-22T19:08:25.140739+08:00","raw_data":"WikiEncrypted:5RlNBsIi2/3o8ATlHuzaYD9/6k0SjLB2nW/cTN9Sp7ydYLe7mauzXPQFm5pYVoY1D1K/aULghB4g32vyxSUIsHV6NsxwYA/5+FQ8w/4xsQc3urcx9OEKeSC0hGU52WXucdAGjiEq/f4wJ2c9FdJEeALD6eX7MltcooFsxAVRWIKzHsMdBiy0RQN6s7vv4sb8vpV3b1ET27D9QlTUiTPU7RgtJLMui8iYiwJIirfL1TgdGRSx0Rr3tY/JvS3/6/L6VU/69BKglW8DnLwDkWKuthI/2sfWQa+lb+uTuixXL/VbltWQnzwjMVYghhTizEEC0xTpFGcDY/ajvLcjy5+wSleNEr9AFy/ytJKkpqEO8Zt5qyVJ4eANJMSXYcoKrZEskjVpnrPEHGdOzaEaCqcl2sQYkXde8LWM29fWmwlMjwJzucGwhudoQLXgkIwJnD+jb1r2SdjjafTI76MM53AnSfD4aj8K26yrOkVtoD6nWG1A1fG6F22pPBhJdezNJCYuKBaSDxJDES5486L5Gm5RvjYDq4r6RZ5CheGPgxl29XjCimgWuxXKVX0jPLUawteo/Vo5D7AHzucx2dX4mKr4rSSSHpD4HGdbwnxZ717DkRG01vTOnue6gSQ7pceMjSZ6TnB7dvtwwarHBKQMKwJXrpqxc83aZQjW4sRTAJs2Gc9+11c7qT9fQnGK54JJjEARaQZVaDmTpKmme4SKKxCB7V8yUqR+D+swVuSjIpYdL1m7THJtbWSSLaKkWmYiom1C6qb4GIgO4CT/IiFSyQ0Sz8MUIJi/dK0l/vVmpp5p3IF5K1m6NHDX94yEPWEHsWIS8eC2B74AyX6PG1fWSt7HpiBAzq8nu8n+IrXPqDege5sXbjfNrbvkRot94AvLF2aqMbteOUGOZxMLASQYyfRQBlaEEFMiKEVNTRSaHqiS8mS3pG6XLcV7TkWJIyMzhcT93hKXrSB2+jLa/rrxxrZwfp6lddgEcV+XZzQU3KsJf8blNUd+UkA4TcwFugu0um1Kr6Hro8EHAR34+FGMbPskEPPX2yd42YXx6qfmcFrI1xvHIQfnc7QuxZwO6GHR0G5LiPtuV4ZSxklXCwgnGWy1lpC13xANNvM1UKqAuhpuV2qU+xayK5IQv7kQaDOJpnMzFj/dSxtRgL2Xm20nH4BA2lhBCQMqeM5OxJ5vzwVlgVMZxDbhwrRaDU6cudgNfRJDFh2lGQqE2flEkvSF7g87Hc5H3qDQxUv56qpdOPJcgugKJtT3Jz4dNt3+eojvEwrTUc7d2Kq4KDTFUa5jDr5uo9PZhNR2TDJazpNIdl1x/64=","layer_level":1},{"id":"e3ae8925-4862-4280-b85a-0b376841b15e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"快速开始","description":"getting-started","prompt":"创建GEO项目的快速开始指南。提供详细的环境要求、依赖安装步骤和本地开发环境配置说明。包含Docker容器化部署的完整流程,从环境准备到应用启动的每一步操作。提供基本的使用示例,包括用户注册登录、创建查询任务、查看引用数据等核心功能演示。说明开发环境的调试方法和常见问题解决方案。确保新开发者能够在最短时间内成功运行项目并理解基本使用流程。","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json,.env.example","gmt_create":"2026-04-22T18:56:47.081987+08:00","gmt_modified":"2026-04-22T18:58:54.237875+08:00","raw_data":"WikiEncrypted:qfgbutC7oyxR6nMxrwk1ODnNMBEQ3/sG78fQT1yXWju83LC7H/jAM8CEAvWT8huE5OClmQiIfNYNxHQ9s7RRS/GGSwI5DTgXTPiPdxvdU9tU52Y4wj4FfVrOtqmH0nMPa+EBKH1Wo4HibSewimTkeCuJVAAjyygiPePcftR4ud09LKmopy1NSgZrtHMoDFDwUOcNJQad4OVgxMnOi6B6z6s2Oh2aPWNJX5EvE5xGkLAc6XvhE2T7MU40VJ4lUOoKlCNZNdI06grEqwyizBqt13Hg20wonqeQ1uPs49UbF84IJecH3DmE6KW3oqmqvQY6tztk79eE1bKZmBtQKXz8WhEMWZwALTsVk+hkk4dH/fcDoLteR1iuO4FaxDwAOaD71KF79AaYxDZiM/8RER9YsajjGSI+sfpJALuiQbqqfKbYFSgliiUcf4gTM20Ey5rtfBkcvBY6yOBPpqdKg7/ls7jdggNEWDJfN+DPVzV4SGAYRD4g/kDzPa5vaNZ6USRa7hVIR0SJufX0DGSdzX5BMh5DQEEyd9svxV+bs4KPZphBIeqAOzvo6zyF9l9LjPPdEook/uTIBHjGgx+8Ck1NQEeNOs61Zqr5EfISope1Au8dYCrzwpr02s4XAb/6bYsMSkfVqETlSSUkipDodGoLJU8QiYr5Pjv63Bb9Qb7SZ+i7NrGp6UJNVT0etywEMKSQn+73I8e9AYrAxlN5ST6K5b3W7cOPzFQMCVRfzvdd/FbuN30u7JXlFCnm6Ee8LDHW6nteOxBP1D6JxbrQirCQE0cSuk+d8OR5tR/DJiRDcjbsG38KVBEqWnIek8KlMGxEt6N3oq2ceUCCLe4jVURPc/2G/6gNiyVq0dPPAVwjaNKNwtiyaDhhBu4T21k9NUfhdQNz9DJWD0wXuaZc89RoqLNlCHJ6TtxEHJ/Sv4cgvm3QUierIBIqUawkCMEDn3ZEo7L2fUS4fMlzfpHSgTvxB43ta+H1m6syFUmAyh1yqfXVxKZY0f4JtmBbQpNzpT+aRHMKKQ9UVvtjvNcpupzO5aNkyclJVWis66DMtfA1H4am2gseXSfgHHtXiLfOnGoELSM1fLS+T9oPt48v+RPafJQpahtNeKtZc4dbTcsc4qlS1krenNSBbkKac4Zsosjv8xHuD1aqYvAS476XT3gjLfV7YUCF/+i3PiovD9NGzhA="},{"id":"c19260e2-5163-43d4-b35a-b48aae995f4a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证系统","description":"authentication-system","prompt":"为GEO认证系统创建全面的实现文档。详细解释用户模型设计,包括字段定义、数据类型和约束条件。文档化JWT令牌生成和验证机制,包括令牌签名算法、过期时间和刷新策略。说明用户注册流程,包括密码加密、邮箱验证和用户激活。解释登录认证过程,包括凭据验证、会话管理和权限分配。详细描述依赖注入系统在认证中的应用,包括当前用户获取和权限检查。包含安全最佳实践、令牌存储策略和会话管理。提供认证错误处理和调试指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":1,"progress_status":"completed","dependent_files":"backend/app/schemas/auth.py,backend/app/services/auth.py,backend/app/api/auth.py,frontend/app/(auth)/forgot-password/page.tsx,frontend/app/(auth)/reset-password/page.tsx,frontend/app/(auth)/verify-email/page.tsx,frontend/app/(dashboard)/dashboard/settings/page.tsx,backend/app/api/deps.py,backend/app/models/user.py","gmt_create":"2026-04-22T18:57:02.317252+08:00","gmt_modified":"2026-04-24T11:02:17.638164+08:00","raw_data":"WikiEncrypted:1O68LCvyq1zgacF3KZk5YThbR7ok3g75/gwtsJvdh2o83INCVjstQiF01tda6hFb+2JTqgZSefMRniabd6NWxIcxLGQkPzKVW/Hd8nBmAPUj7rQun7N62bOjGs7Vdy4RhltwZryBPaspbuAyl910fhwCIzZMGRfD+PXCWNv/v434hWViOvWnjpYaMrt2sX9Ljy71CYMLz0NLL55ClE3+kRm2WBxbzfWvpabmDbKCJIjHUouLtLTqa8nO2ZD/mpn8P/USYy3J+ucCQEsu8jbkFecDJgSCRkNzfeLi54eh7hIPt3cwY3k1GwBPcK28HnOkNGaLuFV5qSbDgUwDBoJ1ZTehKeXMMxAuPFJ+1q+Cushre7O1bOmgO+I80GEecYAmWGgpx7U8Xu3tI2XaqjSkfRQHdUEezEWtGlEdBOV5pTVVkz/k7SvMCf0IQSaeAV4CB0uPNlyH37JexzmbUl6SbJQzlmX5BcDo56/DmhFUZ+iz591eZevVGaIdCDU9scQfmskMZZfkf9d+T9heLb3IonhkwGtoofl1NWkyMZ4LRfpoWpOQVz5rwZczDy6DzPtcmJMGgjGoJF5qad8II9wEjnSfCikdIKBXQM/KBIZKZDvEsRH7Kf28A8nCpNpf9eKymJ9xUlUDXB7chWBw+J9WK5EQplTeI52vg2TWVsMNSe/gBLV0GDzzFNuAIAOAh+BEGM65LlZrL89p9j3rI7YORJ+qtC/f7HdtqWPMDToAOV2WH9ykII3qnNarPzMf6QbGtA9+XEJw1P3fie457QflUMrUyuW1QAW9RXj3CdpyA0XWl7v69GhCW+ABebIpbYBRusC1DkAL1U16hWKVHHgqUV4gf8Fe9Chq1RalQUnIusIyrILaH9a4GAwAAclwJrHhLdDwcGeZYBVyM2BngvsRb/O3ChVyFYnpcM8mdwPauc5jvaBBKrdeyK61TlB6N6oOmNMsnvd+MbQGK9PFBrRFUzkC0+NgBC/hMn84JKFb9bM9QByG7MpRGn3SXDA8p06GgAXdN4la5zg9hm5Zf0B4pryWfgd4FuhV3KvyBM2w4YHORaKYN9xZtxAbX+IOODdualJ0330kxPW6dvHj7fPGxFcUQQb+/tR7E2nO8orJBmwWZh0YchjYeDSg1cD1y+YJUGjn6kBo2UeP1OKt09nDiSlHMp8EuHnvFBQpBxP6HevfwlW1Fg5bwtkTOlgAmJBltJgnn2qJpcbfTminqL9HbR7qWWabkMULUXBRWUSvixoKdphNXY++/I84oDc81EJBNgQz8ZglrU2lOzuPY1D/NDPfzU2MAwNrhMKGcVz2fQj6T4Ritr4wQmQEVRTdma8ST30CO5COXFne2c+0Jtnl/ASeYQcC8/87vsgSXxLQApyJARvqN14s+M1RDKVFG095u2ZXOboEbwN9cTPaDY72E387diTUEL8SKiX2kjnHME/eldUwbnuXM0raDbPpoUSzIunVEWrB21l/8hx823tGkHNjc20MuSe7gaDnYWxj9CZI07jHTk7KM+fVncOW8XC39kS/z+F7PcJbV+22DtWJkoi4U40aX/PuLYs8oyTC6NjvAaj0mgd0QVWF2vvW2R4XGpEIyIZ4Tx+CRzKGE8X9v7ysizR/XX5nLdr42F25yZM=","layer_level":1},{"id":"9b71fe02-5927-4a19-8db8-66eb129ecd9a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证系统前端实现","description":"auth-system-frontend","prompt":"创建前端认证系统的详细实现文档。说明NextAuth.js的集成配置、会话管理和用户状态同步机制。文档化认证提供者配置、OAuth流程和JWT令牌处理。解释路由保护机制、权限验证和用户状态持久化。说明API客户端的认证头设置、请求拦截和错误处理。包含用户登录状态管理、会话过期处理和安全最佳实践。提供认证流程的调试方法和常见问题排查指南。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":1,"progress_status":"completed","dependent_files":"frontend/components/providers.tsx,frontend/lib/auth.ts,frontend/lib/api.ts,frontend/types/next-auth.d.ts","gmt_create":"2026-04-22T18:57:04.21635+08:00","gmt_modified":"2026-04-22T19:09:48.747579+08:00","raw_data":"WikiEncrypted:BenkIlLPgjbiADCpekIm2LnLFWkzmPKE+C+tunEqC7EVMaC4hkq7YX8EJXa9qt893SobX5KrGOKV9QEeDplCQkFx4neCRj4kZkvt/lObxAfDgMBruR7HQAasniGfUhUjW5KYXC16w7brsqCWR8CWKDQGEZiduwEsaDjAZy9TEu7PlK6Cp8RhkPZ9jhN/YjqaxTAq5i4xHmQz4VuuV2SO1LedFcTlV12iJH/vTW0vFyXgJqY/Ql6+bTZO2yMaEWan9rB7e+IsErvp40JaC2xqL7fRnfroIwQssGEvaqckwf2qyNjjNCcewd62C6FVDnxJOLjQbizlBKmbb8XVzuRLkECZVB1edGJKnDV6FkOkP9y2Al2Qtpbx/1Uhx1Lo92eRd57kA0Icc/KGcHKRjNsW0HfYWAtLctTH3fNIwtmND/J/6zKK4UdDJ8sXiTnjiU4JhX/fqW8bl4FVo8F+kJYUIhbJCQkl+qlYh/MkTCmyG8XukvSZGbvWMPUxyU1gMjDxUnyVdcJmFFt15oXI+X1CL6ukGEn1cRRDiB4yRAq2GR4/iUPUFC0d3aqeRj+ryjr6Cp8YqrHfONdwZyWd4hS8RPEP7NeRuD64yNRSDFTju1oPvBfROcmunn1GaAmw8dV6KtXSJnM9SaiqnYutX51ah9psTgX+UxTu7EU/ijnQYUnDLg26m2/bX4Rhm4MRyE/fAwzxOKEI3uIaqyun0W3lgdaF4bWTwTblet2a9rBOwbVP1xtJ5M095JzboruOAhl29fAT9iO2jeqpZBoO7zBim2s8cpkCt/Zf2Edu2CeUkS180PzKCBtnq0FpPLD9hjXPsn0GjtTEbwO6lSl9JdJ1+J03tiLVJjRTZffLUlA2gM3tucbJOfyGdAom4yffwP8hjrhTBeEyLwKmLISNARiKuE2Cm671yMn1pmt85Vu1rajq9L/GeJdoPPL+4pw0dk8/Oydx0+kOg8/Jyb/8D+XobOK98UfLB6gCaeqZV/2EBEumn1xdhcDpP8cx/kijjzPmOg+tlXa5VzG6SpcY1zw1kYgyEbLZMts5EHUFYp+UCNixZleiG2HvEN5v2iuXOdcZiguCFkQLt9TkzO1v99jj08p64LxUkxY7ovJoeanwleMMBEAI0vWrt1+8nf065/WLA+s6zQWMP7nlMloMXAfMybSF/he7s2xGsrnFXqR0XBU9qRnrLY/9IcroEnKTvicyEUylh+wG8KUQcIJj+fOEVqPGITla0i+36wx46XgzdRw=","layer_level":1},{"id":"b80dc237-1a6a-401f-9f4d-14190edebcdd","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"技术栈","description":"technology-stack","prompt":"为GEO项目创建全面的技术栈文档。详细介绍前后端采用的核心技术和框架选择,包括后端的FastAPI + Python 3.9+、前端的Next.js 14 + TypeScript、数据库的PostgreSQL、Redis缓存等。解释每个技术选型的原因和优势,如FastAPI的高性能异步特性、Next.js的App Router架构、SQLAlchemy的异步ORM支持等。说明容器化部署方案,包括Docker镜像构建和多阶段部署策略。介绍开发工具链,如TypeScript配置、Tailwind CSS样式框架、ESLint代码规范等。提供技术兼容性信息和版本要求,帮助开发者快速了解项目的技术基础。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":1,"progress_status":"completed","dependent_files":"backend/requirements.txt,frontend/package.json,backend/Dockerfile,frontend/Dockerfile","gmt_create":"2026-04-22T18:57:13.329718+08:00","gmt_modified":"2026-04-22T19:09:54.216074+08:00","raw_data":"WikiEncrypted:w0CkdCdnXCcvlN5xOpiEhEX3U68GI0Ngj6azFMJo9xRSxuOblJXg8Gncvj5vankATp2aJeXH/Zz4LVKH2Ep+cABEA0J7OIJMnt/ZJc7uvMtWJKS6+i5aGsUhX9BZcr1SC4TqdgwXb2je+DFK+fLZJVkri1Ne9BkEqmtSaV5CijFytJ/VSKFHzj8+7gC5Jd3CbEASojclHovCufD4dAVhlK2qcIuY3RBxMsvfRAlLyMLZEWg/gD7LEj0JaChWWR8vRaEtX0LtMoYIgSfbY/nUjR+3xHFig+m0qclK8Q01S5GJH99paLVqVkmt12iwMMiqNZypY1W2gRvZNsT8eanIKu0tq5HqvmbN0y9+nnuwnz/Tg6nUBlKIIS40jp2oYca9ak9bIwBm0TqkMe+M3Ara03+x9PgGRUuYwCt9d0PwpPG5/vOAkZtP8talqqwhn7Qom1nVkhmExMfsXTYsM+Fn2bQFXKIT/rAyT5rY6hwokrvghKwOb9pH7V8+4XckeKWV6L1rNcccOb6Inp4WcVBTcTvGbdy4Wj5Z1VETFwMnDdpOGFWc0jZRJpjrRSGgDuEW8IXpMvVYk3FV5ZyUXZcNyEWZ0Fp/s84guMC21/RYF67/9jD7eJYMeCsU92nWm6QkdVB13XQBOvYGFSu1QejQCgDMWpPz4kkt4yz9mgOtH7HsH8ZUDIml7Vci6pCcEIzS2Sy+BoXxSxcOzrqxD+PbGcH8A/BafN1771WuNzprCCTqbZd5MVXBKiY+qrlRCD1ug+pKS075xfWh/Y2Sjz4p1aJuyVplvOfNUKTlbZVBzQu5DBO+yhXj4b8Amf7OLydq0Avaf0gJhYhX3HpFNqi6aqT9OzPBIPohOUi9RWffBwHMJii2/NZj4GbgeXsWU5+EKE6sGFRGtUiBZGzf8FnB6rW16EA6in7Vd7Ls3pJrra3z6b/k9gqlh8eAVDoZhCPuxtA6yNlXm+RYWLDYeWiRDZoavKVj13rXtaqtX3j1/e1zFPMBZlDPVHyBqCZRiZjlKnty9cj2ASgpu7idyh8jDQSALGu814Wb55H1q08bvFxJf6pxn0JfbRJZMHqCEgInivdDUTcCCPOteDT0O2pwMmyHuq3mI3VzFPnYLM3aYzgJQsNIVztV/dIEJu2UGF/cyjIeROHaxvWYLNXRJZ05iMp8oelEwNe58eAvWt2KOuahqQl6xKUctm90QLv8QR9hr7PjiNAMVH3WsMxkqLcIUPuboMElVq3ErUqd4qE7W5l5Uxi2I9bVcnq4qiRtbCnRY32uC43wILTgq6KrBaO6dehB3eW4drPWqtmcU8rP1DJEatUWEvhpDNrI7T7wG6F+","layer_level":1},{"id":"7e5c3b8e-5aa3-448d-ae52-d5a96a413b0b","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"表结构设计","description":"table-schema-design","prompt":"创建GEO项目表结构设计文档。详细描述所有数据库表的设计,包括users、queries、citation_records、query_tasks和subscriptions表的字段定义、数据类型和约束条件。说明主键、外键关系和索引策略。文档化表之间的关联关系,包括一对一、一对多和多对多关系。解释业务规则在数据库层面的实现,如数据完整性约束和业务逻辑验证。提供表结构图和ER关系图,帮助理解数据模型的整体架构。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":1,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py","gmt_create":"2026-04-22T18:57:14.160671+08:00","gmt_modified":"2026-04-22T19:10:23.576798+08:00","raw_data":"WikiEncrypted:TWtD9cYU/QQHU+vD+ojNNl24L1Ao0zI5Y2mk07u9ZlXGce4CUXsGNCSRaLrvDZHw4OUpuZEJrmJBXEQX8GmxRc1IXLTgRlqUGmpzfcUAx8VrQijBe+unqg1mWTkYnMlYOqKWSJdISHyD5K3kBL2cL5pXF+f+lPHzSbWtqMnNnMKbqnSl/TkKh6cr7PM1YBR4IYmE21gHSR5XoQjbtYmg5qNyKF1kMdcAd0LHw6p7zHBaF9cNt++5GyFKLK0zjN2L8YiFsuFBSrn/M48QW3WyTrvDvqdOuR/Slfv+gUsKgbkt6+NEpuY9HPcRdvVJHvG9FZedomH4DrKuI0fUXgICXotXbrcEe5dOkLKgfn+gXmS6sPSZ1XgrSNO5gy2QNJaW+oKBuEPzfuKsNr3X19FZTz+x620YmL1Ccv/5uvf0Zxl6fyQb3qP+lsh2kaMdhWVKyoBv37oNKF7MO+fy+TWHFEwlVnxgmQREyQva5qxLyYzu1GtDpGp79IemnumltTAAzQ7LRs/RsaNcU3BZdYfQspjnhukylPJpNZtmKNN//XWvj023bGiaLyy805c71DcyqZNUs+EdlXmRTABeq9QkVU5wq/gkO4RFSgsWao/8f2i9FLeEZolKQXzoLnX7GxaY3BMcynG+DlwKFEolVOw07cpddYEWzmVKgJUokX/eiMbrokbcv9bLXJpHl2aP27B2FXy5Q2Ot11b2WbuT532RndBI+S9HQpfMmZ2z2Fc3VrWAbk03DwChHEbNHpmQvJpjKtLweVEpClahV8iTSwCkwd43jJdW+tR00iSdjt5vbl1cU7Dciah/B/9B7CDr9sUyZMjly7kzyWZqTkdXde3tO6tu6tWhTigIMXmZVqhW/pgVifH0R72VuM+sdMw57m7Z89ibQ7o2LewlMzJ4GsV90DdDhHQtUr++aRhcZp/669o8mijOQKj8MPHY+xjhZ2oiS6RHiCYxpibVfauiaXA3swWKIQrVCVE1x+jB07pieI3wHrmZf875mdp9rhfrz96+y4zJ464iINUdTQinm/zI4CnhXE3inFBgr8bD3pop0oYr2X5f8Gn2iKyvByc+w5r8HKV/7dd4GrdAosqVWpQweVEYR+MHRZ3AxiW+TCpRWz/PsHgunD4m+AQv5lxwoHVqF0Tqw7fmmxTqA/zC+dxlIJVD/R2WF4sFpA6femHOwqniwaowQerg8bGe7mz3BCSqiobqGSZQ5jQdh34TRP7qUg6PGkJx2NJ6AVIZVYBg9JNOQI67+2PN5AKq6WiT7Rojgo1r8lEx8SORaVptbL4YEEeD8Ec4g2l7Aqkhdxd43uw=","layer_level":1},{"id":"9fe32b83-3697-4939-8b10-524f5ed3e65e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Kimi平台集成","description":"kimi-platform-integration","prompt":"创建Kimi平台集成的详细文档。详细说明Kimi平台适配器的实现,包括Playwright浏览器自动化配置和初始化过程。文档化页面交互逻辑,包括搜索框定位、输入处理、搜索按钮点击和结果页面解析。解释错误重试机制的实现,包括网络异常处理、页面加载超时和重试策略。说明浏览器会话管理和资源清理机制。提供Kimi平台API调用的具体示例和常见问题解决方案。包含性能优化建议和调试技巧。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":1,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-22T18:57:14.59267+08:00","gmt_modified":"2026-04-23T20:35:18.737652+08:00","raw_data":"WikiEncrypted:0zvMywNpoUVtx5LPNkwYYfwlM/Ie9jv+tKyKKcv1AxRC9mVBYjtaMmDbjB4bi6R3DoFVGOgv6ErdxCywJprEc4/FOXSuinoLipOBEjS1SoLvIuIvglY6l/IjgeQW61Rm7d1YcswwpmQZIzWMvqp6xJswdQOA6I4OCWZyyoaPa/2lETrzZcBW9ssD16KyXFVp96WbqY4mZhPFxSQEDiT4cUJ/clUzKx+oT4S+pSOYSGl6/5YsuAOA3Rc1HhY9Ow5FK9FlKsVMaFmxyJU/KLHcwZslXi8yzFzIWcnJQnRmMQlz6Zzz6mhJvkfg/s1TIOTiz3ZX906YG6DBXgZ66UywONJCeYpSAmTL6PJmP5z+lNRhuD0CzfmDGhErgZhLtvoyUfFoVruQmx/x9Rgy1lFnhKmvH60xIEg1eXiVjrQ/yktlr5ioCPigx1TWbcHspNlPAbDuKqqBhQtNOIgnlpoGgyEogad7Il1hkawUxt/TaiS3Lh0SN+zWs028ewgjO9gdWMB7xsAiB1+L5jMFCCJP/mhbPEfqnGC/VyxfevmgulrRD5A2EPR0QF4D/XNbc/vqSGqnIgkBngdxV4ibQlp1HO+Av79lh88FpVteFuEf6bsCL5SSHLDhJ8seJm0aoD1e6f+DtutdT3mVHaMcrEbMYz3AaNJhbNq0bEuElJ/ANz3eN0m5PPDjjnZto+CQ9o7K0C3DeRqKx2P0uRlrzhuBWIwJMzcC944SPjxYEUXHfT4C4vryztUifweDRw3eil4eFCrCBpGf/6gsdtqLoTPs1uBBVkxVh2UFoypvq5jwW2g9IkwMSHN/sAbNIITH2bRVDR7Z/pJay1eQSTjF1pz3NWcM6kQpB22XVAiOhiWPjJRQuWDtpRh+kOxWUSLaNkXSsf98tkydtHAPkMfUhalyLYFO/66PWyHJDWdFPECqtsOy5mpoJdYD0O/20+xc08z7liVDDgIlSocFXHWG35upSCjW6JWCIiphXqsI3He/dWHuwvTBamA9XB7Q44hTbQY3lKiTRjkbjuNfX8cmxcX7Hq21kTW6OBbxTVR55HSW1znrOe12b0sUz6V4Sk1zI5OB","layer_level":1},{"id":"cc7a1f1b-c70e-4c61-bfbc-6dc408a12ff2","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"查询执行流程","description":"query-execution-flow","prompt":"创建查询执行流程的详细文档。解释从任务检查到执行完成的完整生命周期,包括查询状态检查、数据库事务处理和异常处理机制。详细说明check_and_execute_queries方法的工作原理,包括查询条件筛选、批量执行策略和错误隔离机制。文档化单个查询执行过程,包括CitationEngine的集成、异步调用模式和状态更新流程。提供执行流程的时序图、状态转换图和错误处理策略。包含性能监控指标和调试技巧。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","order":1,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:57:25.383473+08:00","gmt_modified":"2026-04-22T19:11:29.353795+08:00","raw_data":"WikiEncrypted:l9Ho0Yh0r5bYH9QEePEhka2UMFH582eHsB+P+EaGE/r7Zj5gVUJmL6923rRlAt7h2uvHOVtef4s71D/S/eYpYYgI+wRFyPq+fQZYOCmVnMBRyypO5m8WqfyrsSGvviugw2fw2oH6ruNX2ul1LjPKkntbj4o015R9XwHG0oDdyJlipxqNUbh66IV2c2DO1besCA/q2yTeLh6EiHD+vYeG3HO5H+y8kykMbBuh9eydnmoXBTCsTlNBHH8gzmZWEBBSL7DETM0lYCiNr6WpRCoeZEo9ewLagGq1ammmMjcMg+7fO/xo+ZkkACRTnG2vnKh3if5fBjzo9tY4tGmtF7Fevx+yjLRfhpPsg8vSRZeaggRPgub5zBIulo/4qZhAvIVsyYuAQCqrwq6mBxAEjgWWrWjOThUEQOntbugUY0DitRui7XGp7tDjAIWw570xWzTTUWe0CMoHIPghfvhItcnYfjKK+fapnQTnz159jVJarLbBdjZT5JJfw9a+jlkVyF5RIKu3J03cjGFJeBf74DiMxFIMQkKzgL8jg5YiLQTisI4X0BBQrKHQvHzsD5+VzHGwCsz7IIfcdZuhkg3PIA4z4V7eZP9tOBUJdh7iE4fjhOk6fVDG5iZME72OxpBtFkmfrhwM52swaToCosj1eQ5m6V2GjsYY/+ZvaNf2aWn8vBJHI4IEO+Ua1mLHkPRT9bhDGS+Td2r1R2fmSEEvNQ+PTuhnRAyzRASTsjfWljzNWGNmcbCtClwcIuTSwPWLAoL+ANl303UlvxObHa9udiJcH3pZ86+A7iBLoCg6JxZQuCSqD0W6bPR/vozpiCvGs1TvMR5tx6AtfZGWw4JYl9wN5iPPaP8sPsz40D4PWkYIb4fIYY/X3r2iAnbjpV+/8+h3DQCWEdqRNnkZ4Do+XZGOi1yH7QaPOf/RN00+bcNtR36PnzENY47tg8VfPkbt47YTWHf+qvWfMFPwco2hLzXvNFmYN4dVMld5V+9mzCPJSIb+JOcDoVkoGuNq7aXnOVFdERnypgzvjryBt3W2LgPNlD3k6jR7pJAE1gKKrl00VSdDN9npu4QXyT49p+YMv9m8Jbf9xo1Jn2dqM/cJiKZi1FLR0clZHZ7nh7/7WxoEqbKnLWbboi/qyuTABO07nyQfmyXR/24bRp3AIRiM+7Bq8KL9ZFZs05JmFBtaRCAzWdBdM3TElVkfFOyZRZeKaBlk","layer_level":1},{"id":"fec685a0-c9bb-4048-baf4-40b56b2aa29c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"集成测试","description":"integration-testing","prompt":"创建GEO项目集成测试的综合文档。详细说明API端到端测试的实现方法,包括FastAPI应用测试、数据库连接测试和外部服务集成测试。文档化测试环境的配置,包括测试数据库设置、异步客户端配置和依赖注入覆盖。说明如何测试完整的用户工作流,从认证到查询执行再到结果返回的端到端流程。提供数据库事务管理和测试数据隔离的策略。包含性能测试和负载测试的方法。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","order":1,"progress_status":"completed","dependent_files":"tests/conftest.py,backend/app/main.py,backend/app/database.py","gmt_create":"2026-04-22T18:57:25.616681+08:00","gmt_modified":"2026-04-22T19:12:37.820526+08:00","raw_data":"WikiEncrypted:0j4RRfWJQdenLQLpT+DwLTyjMVG5sQffpuJQoSG8tbOVCukW9eq2bqobYYACR3zRn/N/FP6n0t+ZzbrLBFIDPbiPv5CjhNbth11wsRap1Da2YyKifcvwg7uyuWtSILKRIkP8wIVHX2/TkxRFQi9/m+9Qz3xVjYcNeOD0G8UWxzsSDqYGS90xX9MVwW3N24hbwwcJUE/TAMETdbhwrekpr33ej8R6IT6aBvn7m0Y93BRItueF5HJcUtKCizqJqcsG+BIQ1fodLPAsUiqvYW5dwymM89ASYiZXVbCOJq19yL9K4p1ZW1LsAc2J+6D8SR9RJ//D4gGwBmMTqxyP9bgn5eNt3ILeVMXWLXI9oxaDrdVs2Y4dXNC4AK1j0pegZkiNREUo54kWHFqCuQ6dG8dZB7BmnFEIYjwEeU29KdF6i0dyUH3/h5QjdLfc0OV75zuHQPaMs1p5fn3vo6ubXz/uWtxEF/IoVhph+AyY0Gci8TxdouTw4RZOm9I6mo5m4Y+TBsxUb9RO0WCrD/U7tRgIZcrxFfkORsKadNWm60Q4SRJeImUzxIVCUGBjr4km9AMwVsl94KSXmkBCNOFppeijE4N4Dl0n+RekVA2NBOau2woOIr/GwJ7b2h0jV/5/3x5hihxUSqZJ/q4RJmV/8aP30XRdYwZ6qiLcaF6Ic8kwpaS+9cvzGsPMcUF4GCS6ZSZoq4tuGj1ZY/iFI0w6Wj7rJHWbeBhsF/fHqFm2ijbrvn2nz+lH8Gxb3FM+re81hKNVU3BaZ3fxOAldPPvUxDw9tttWR+oH3F/gRkqefOIsw95LNYf2vIq/HXfNygn6mUw4aYidP1SY8flPcCMl0mDm7y7W6l+DKUJuok11v6h2AM09f0VV9JnGBMgwCic1FjQmfF2FWdqlsEaB0X4+aPne0DgPyIivgCLEq1dyneDm4TxA3CEVODVKHIu4fxPjmDtwbXUvPQe5sWkG7AEkp1Vuul8T/GLjJc/DHgUFe51MPFk3+8i0FCKo0x0fS8Mqm3spHB5W1tKYAIyexOgSkHzqgRdgERCTqUW461c4lKbFO2WIJqWgt/seMgxHr02Yk/pvMU08AaMRC974SfB7kP0lEQ==","layer_level":1},{"id":"b10c2334-a850-471a-9851-a1c698e3a485","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"查询管理接口","description":"queries-api","prompt":"创建查询管理系统的详细API文档。记录查询任务的创建、读取、更新、删除和执行操作的完整流程。详细说明查询任务的数据模型、字段定义和验证规则。文档化查询任务的状态管理、调度机制和执行监控功能。包含查询参数配置、定时任务设置和批量操作接口。提供查询任务生命周期管理的最佳实践和错误处理策略。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":1,"progress_status":"completed","dependent_files":"backend/app/api/queries.py,backend/app/schemas/query.py,backend/app/models/query.py","gmt_create":"2026-04-22T18:57:37.836674+08:00","gmt_modified":"2026-04-23T20:33:57.631967+08:00","raw_data":"WikiEncrypted:pNRlLcrWPaMbqj3wxGubppFNc0/AzaZuAQDxEKkb9fgIpRlV367n+a2PWiIY8g+kSLtBeyylocxMvW4jGcb79BLGGixlb4O6TPBIJc7v8GgK1UB+nLdmTHx/nT1JfKtrcPOkDjQ/yPHvw+ykuXomGaA2hiHzzBxAe+PbZILYbxYpQjnTqh7v4SGaGQ9U1E2EOXJ0RFpwna+s0NYfvBk+YvwkzRYPMiKcr+F4pcD5xTUWKMHZO3NuijnbDIE02fzYXvZ/xDBLubLxQ9Byx2dgdWxmi+xwo+gspb4v/DcrNll6qDWKwDnHGuyOQzDJJ1vXg3AaxwF5c2JyyQLNPUM7YV2kwxweQA08sFkJHAJ2yA0z4XM/DvAPZRdQf54LPlDB1zuFh8c3Ih5WaEO7+aTJM4YSmIYUbqjIjbqsMea3+cY2bIHXq2kdRT7uLikCktC9Lakrz0fFKLoJLovY3S1UBP3i7tCt6cmtMlN5g5hyHGqIVTT/fqAVUAc7wSZumMs4rr4uyEizs6t12KohwD2SqiCePMC+kbUpHV0fEBuzGlnYqPbW0yjiiVQlmIe8wTDNiNNa88JmcXkQB1pYhkAYrBUvBUN4Nrdf7lGBTIbQkQwvVoHuFah0MmoLuRQtoBqISkKJ9PMN0EOofu4pUNKyxmmcY87ZVbUNrwkgbvahp01NhzlsOLdxEa7d/74gFI+6MOrPY/6TcJqttksCQEkme4HWeJgRl5S2bCy3hlU9qcZyk6WAGPjVZg4JXdq2UbvBokHzB7KA7421mWkKGQALuZcUApNvwsvF1ZHjVau13wxP02WvaOzt+udwhgw2PXdNi26RDqwLhRL+GIjkpNfVngOcLfk1ULiMS87NXS9kHRTdXxu5W6PqAzyrgByrL3G+nPHL+XmMw6ntgsJdmtYmNWV0VijOOQGxSJGQHtaif6ZhBP+ckr+OXJ4GlkTF3jvGcfRkfx/eox+BaoxWI06xuXbFfImPuNqqa6odgzQzWv4CkvAnjcFq7umhE9Iri8xw/PDlUzBnr4HGnUPnAVvdomeMasz/oiPVTaI0O6tO3+I=","layer_level":1},{"id":"0c1d3542-92cf-4796-8dba-82caf2f7b361","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发流程","description":"development-workflow","prompt":"创建GEO项目的开发流程文档。详细说明Git分支策略和工作流,包括feature分支、develop分支和release分支的管理。文档化代码审查流程,包括Pull Request模板、审查标准和合并要求。说明版本发布管理,包括语义化版本控制、变更日志维护和发布标签。提供持续集成/持续部署(CI/CD)配置说明。包含开发环境搭建和团队协作的最佳实践。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:39.374243+08:00","gmt_modified":"2026-04-22T19:13:23.08237+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9Czfqaqo1gAmvHQcnSrNK3eg3bg6SLp6Qtm0Hd5JwzGY3jDj+dSShAoxbjZ6YvxA0ahjJ7+4npTrro/p0OlyQfTnVZ5PYAZZMMXhJM063eUYiuQW88+rNBbc3mKbsAdZboYndBnd6/wybElFnP7TORa5qWxWMveWf6U7O01ocA+ZnrQqoPWB5xrRfSzD1p3yGFA3fzKobYoxAAA3xE1ALEY0vjLN7vajgFVllC2Z6uKZOE4Q6v+W+r18Pr7pLXGDJM7b6pEfFCqcEMw2fWzUAFYSUOjSyg7j9TjP6Lae0AWOmmxIDmJIIiaY0BCv/iOXgg4F6QSChC8bZFyWJATWTNhfmHAMU6tYpDXqDsfLmRpczznZ5nzTtcX+87Ndpqchh+NWU4y5OYvzEeMRCh3HcCUDs5KrOoCJgRneV8BzAxfk4gCwSo2t2D/FYg1XWGfb6hPdmWzePBCYhhIGeDQRyAdApe2Js8UhXUOD3TM7yzFPMX9q5U9ZBfejCp8TyW2thbRzOL4s5Fto9PpXg38HbnE59l0BmptA7z5bTKTp4DHA8d4NhgCeDbfNLfSJXbyYaD3RqsQt8szzbxB2Q8mvEi8iUZUARZR0lyq0oEw3cYkZRo7Dcb1n5az2OJRZwHmvRYAm7KceVqa92aKeBUlVrfA7nOuwsVH+cEXyzE8ApglbJiQfTJshljzVBvYPkz0BxhBcYrnRIjy9TlqfTs67adZyWc0wqEVZeZhuYHwwN5yID2imZ/nq7cqiZCbV1dtBUUM6ayhVX2h/cBSLpHKAwVHAg9bb9V+RxXgtSYWYKCHsAD0ymmu/Fzk3/QBvrrFiVqL4b/5CKqk6Qi2dh4pN4tZg3zJZDuyx6xzWSrsHeYGnLunZQWtHn2lr2vR6+RqzRTDiOC8SizuAjeZP72IbQf5Xyyf65hS6yls8xztLA9oDCNnSDgJ/RiNDOspfgUyj2xemyoNqf2eJ/kCDdo4/VXxMiKVfg3MHY+Vi4dVlRcSEJYLU4AYuGqtqVhTIi2ESpnPXgDPAIT+ZZPqg0hLIIPx+HNqo5qz0qqxvliLlcAhizNT4MG3p3dBRI2IkylW4gHg==","layer_level":1},{"id":"109a8fb1-6619-4bc7-8481-e28cc2127d24","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"生产环境部署","description":"production-deployment","prompt":"创建GEO项目生产环境部署的综合指南。详细说明生产环境的部署架构,包括Nginx反向代理配置、SSL证书管理和负载均衡设置。文档化环境变量的安全配置,包括数据库连接、Redis配置和API密钥管理。说明生产环境的性能优化策略,包括静态资源缓存、Gzip压缩和CDN集成。提供安全加固措施,包括防火墙配置、访问控制和数据加密。包含域名配置、DNS设置和HTTPS证书申请流程。提供部署后的验证步骤和性能基准测试方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:40.355193+08:00","gmt_modified":"2026-04-22T19:13:58.697418+08:00","raw_data":"WikiEncrypted:1PcQ+NupkgQiLQ506NXlaizhNZeqS8C1INCZPnjb6ozpR9JAOMhzbAgtECu8k4VbH9zFlJ7iHctHtUva/hpzUaHUxVuG/rnK2RrcCUGVfbG0WKRpjG+EsQheC10ihbe51Rb+uXm+ciY+/SOxWBmrtK9m9jwSBQZQx2vXLOPvachfZTksEB+Ak0/Y5DF+vjL4WN+ym2SAYi7dW98iM9YCG0AepSeRm5DxENKRvtPR7m+w+vL7F2oISKi67pFiAATpFXSSgbkKjENZIgPfqc+pJfUREOrnHANiCx/oVaX2aOb68pluM8RGtAgyOfMp097D2Nt4PR/HN691JphbIyyeHPc82yGTjeuFPfg5XqFkhM4gvd9EdBLE3/6bh/MJhYjEwmN2RRhz7EYgLjSss8gEdDu+YLIEbHIaIC5fFS7gss/cJULC0/i3v4nnobE2Iqh3WdeIMAmynsin0sjO60LhvRmXlecODQ7+1EeQpMWju5LwTuVyX3dnr4CO4rJJxEBNYA4gaJuef2xo/ZXoun6cEIHjUq7qVNVOBZw2QtqBD2CyY3NULBP+nDD/NwjH/Gh98gl2Q0am/gLAHHoKcZfkSub1o1m1ZWTFgYn6MqyYv95NuqxR5+MSPb9C6/rwkYduPmovFsS2Alznry8TjsLdD5iSNz9MdRTR9iNV/A/TIIovgVogXlgCwnIz6EXZUgDnTeBTfTHxC+gwTrSKXUigRlIxEGksBJkzktpQA8y9mwnIfHgRDI4c8WEQRGEcKm2N3/ZPVOyBHSOHNpXK/BX8MCQqGoj0x6jusO9pJehw7KRprktlMbB0LmAuc5i0RYf9SnhsGs23W7ktzhS+uTjRB4kviSWZdHs+hgh1Pu0HsyBZxX7pemalNElQsWbvLwFNsJY1L1yjHNbBDYyXC7gZZqdb2l9GqKVgozQuK+qUUA0Vj2o6Cr4CxL01vBYMFpHALv8KnmAI2CuprX0c6PmsXV20FAFF8tIxoGfh7qcvquq/d4ONxZ5FZ1hJPYzi2xeCU0p8gFYEYYlbGMXdLCk0L5Tu0aDmTVkkrZlOHSIneYJDGZ1W/q+U6W18i48iBLvFBHD19jGHBgdzRuX551rbt4axStOcEGuyFrivbWK9R2zdcffHbiRtxe9wSFXxthLGe23JR42EF5PmZmMtlUhpV6alxUZNxguf+q/ouSz7Xn8+o6amnO60N57RyJjJO7O6+TgfHeroxL7CpABxkru/vXEJ5XTLqZBiECMMi4keQOqUbNZX8Ioct03e1YG7OgHtDSayZFtZf3kwN2ToVkxIRpLHTUHxSWLZu0YiAI2MONU=","layer_level":1},{"id":"4d5ac6d7-8812-414b-b8df-68574cc36d7d","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"配置定制","description":"configuration-customization","prompt":"创建GEO项目配置定制的综合文档。详细说明环境变量配置管理,包括数据库连接配置、AI平台API密钥管理和Redis缓存配置。文档化功能开关的实现机制,包括动态配置加载、运行时功能启用/禁用和配置热更新。说明性能调优参数的配置方法,包括数据库连接池大小、异步任务并发数和缓存策略参数。提供前端主题定制指南,包括Tailwind CSS配置、颜色方案定制和响应式断点调整。包含生产环境配置最佳实践和安全配置建议。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","order":1,"progress_status":"completed","dependent_files":"backend/app/config.py,backend/alembic.ini,frontend/tailwind.config.ts,frontend/next.config.mjs","gmt_create":"2026-04-22T18:57:48.684725+08:00","gmt_modified":"2026-04-22T19:14:17.843426+08:00","raw_data":"WikiEncrypted:aC5ZtUyEKPSxjzg//aVllKOp167MIMMk/Juev/hVoGY4+Uz0exYT+x+CbyScHHV/Mh1WUG25XsdoZThZQEtO0sLOn9+hGddmRIK1DWfKa/hxxPvnViNvXvltvNYiLNOIbKgkBxtXovEsADGNyhZh4ndOp+a/upcB9NJ4f0miwJacx2Kc2MyCkDCgUM/gJEjyoB9tRPRJVPFRvprzmaiPXJ1K8jd+KuXwrM12ogUA9iPZOtJJQTeEXQVIItOZYzY5bzAZ/mnRyVIB11vegQ+E6Lzm7D1Nza2QOZ2893Bzu61StECZsNlfecc+xEh82aNHrbFip7Fg2I3E3fqBs5EgoNXO5Wnvkcd9fHCw9vI9kMJucTIPcthOyWAFiP56zu6Hzknqy5N0o2gSAJQdhzzEvIUUKeeGDZKSY2EjFsH531gWa+Q9m0FsYWFcErqBlQXG8K06rnNNeMwR71GloOifAK0ySuik/7BjJ7xIR7HF8FOfSaOhI011z3GaEBxZsMfPc13v0joKHld4p4PRBXAfExWLlfuM6cmB/77U4xdBrHVyMcS8NPKuT+TQCTzjr2uUKzxUcjbz+yGbjVFGKMaVzKH0UQfLKeSDUnb1JNBrQWR0PFAuZsPZt730dAHdElNx9MenV8/GY+XPklTXdGMUtflT6CKf3fLy6ppMVbMDph2Ov+1Xh3z35Y5Mz3rufJasyOE0rZQMNsUu3wHtnjYprxfzvmpP9En5z4KoGEa/282c8xoLp+n3+etuGCN2aor1BSrro/ZpPTduyQtqj2WdfXDnZo1In/RRAh0TwqPze8Cd244OFfKDDAEICSSoZl0S/2l15QyTbqDNVnRzLndJswfAi2yfaVOEkBHvZuDQZXmmlf4VGsJYihVUwG8Y8bvegjLxgcD3LFGNKjzuKP1eAYLcotF84HRaFwNG3hz8Mv8puFMKyrHVKIC3UxzBVaialQqdO3oFRcrLdcSIx1JlY2qhK3BsrUtj0OLURUs0dBnCQS4ndq4NTLSQECFIifA9l7GSPXyOkGkp0+H5QCfjOl7L/3EJ2o+lTisAZggIZSZ57Ig3WxOGp4tgBh18ubr0TRNi0u/VccTbFyT97irQVq+9KNBKwPZZazaWvJEuqNSsdX3WGjh17VTbbZgmTkAwLyuCf+nyKkGUkq6MtRYwX17XkQuhceFpBmYkoxlfSWr4odGaspQ3c/AJ5zFNMigymGGpxOynWRWD5Abo/3R67eqZ9rZbmCqQbF0fkFPxdi1prJr87dubXtG1Zkj8AE/ZGXYjwas/l8NeDYxLFeir/ic+yR2tcU34lFAY/B86IHf+EBSbBYigErIEadb9gw81","layer_level":1},{"id":"a232faa5-28b0-4235-8ad4-b082fd226e69","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"订阅管理系统","description":"subscription-management-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/api/subscriptions.py,backend/app/services/subscription.py,backend/app/schemas/subscription.py,backend/app/models/subscription.py,frontend/app/(dashboard)/dashboard/settings/page.tsx","gmt_create":"2026-04-24T11:02:30.91857+08:00","gmt_modified":"2026-04-24T11:04:05.339576+08:00","raw_data":"WikiEncrypted:esVoUJ7ZE3JHzIVFBls2kBN3sRNq72F+2dVFRiBKd+IrKVrEmIv5onipM8erIVXb1pP69wHz5wuM2zNLXG0Ok25RXMybvVHkFqWAEJZpvoheUZoKQmWosbt/UANV5ZMnjhjv0ugRLP8tCwG6HlqUXa4nXCgq5eT+9CKzBTZAc4gf0pl58FewLHZ717UOV2vGW8V5Sc2aVmo/U4kxF9AoGPen+UMUBOILg3LRfP1EM8uA0NcfMu0/dTEUhVAoYdg3egrk6V0LTUamV5NV1SNEVaJfKvMAbt0cYc8sTySSeM8Snn/OvSpnZV2OyrhySqbTxicufzGyCTg/r00/80Kp/vQ96wbKsGjdmbm1F12CjGpKngHQMvn6jGX1n4TtKe4WXqhzWD8nSBjxmMuHQfT8IIpn7seKyIYsAno3TuGU8reVJsl4T9zxMpyipiCssZHp","layer_level":2},{"id":"9ac86c99-3b7e-4745-bc95-9586153d616e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"管理员仪表板系统","description":"admin-dashboard-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/api/admin.py,backend/app/services/admin.py,frontend/app/(dashboard)/dashboard/admin/page.tsx","gmt_create":"2026-04-24T11:04:06.082629+08:00","gmt_modified":"2026-04-24T11:06:01.089787+08:00","raw_data":"WikiEncrypted:VQqnnGxIj1CWE0rWwHbIomxfew9b7C1uZnUxTSvoHNsF7jhPgOFZS93QZowJJe0Bae/WW9gTFISgZqZ6JAIQlKjp5+H4hYIxP4IyhsAvFP0LcPKdx9gdtkqMwGuidWR2jaXij4fO24hbtjQmmqGXzUUbNnTur6SoiIIKMQ50UFibNp6+YGkvBNWvYJucvpgox24f7/W4o623WN3fB7olfkunOV4HVtCrMdz7LTroAFTZrFhDQtadQmH2JKYCypsT6SHcUyxNUvEZKgLDm1LnOAV0ZyfEx3DuALwEmdt1djL4f0HygoGjNMpqhiA4vnlg4puNMiDyY1yoIUNQDPK+RQ==","layer_level":2},{"id":"d54446b1-5984-4fe6-8fc1-ad0322ab7914","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"安全增强功能","description":"security-enhancements","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/main.py","gmt_create":"2026-04-24T11:06:01.807432+08:00","gmt_modified":"2026-04-24T11:07:19.927506+08:00","raw_data":"WikiEncrypted:6g8iffgXzed698CsRven+bBahvPZ7dIWZ8oYo2ql8SUqS81oHqMdt4/8dBPkLJmUIV4rpltw/NKHLMVVnedRfw/FNgssHH7lJc6ouSeYuFX3t4LMNLJCZkqOnMgC+EkvVhhY7xeMZKjKAR0WN5yHtQ8nh+sWXX5BRoIgiZVs+G4ejsoPo06ZZ7dCm3NkqT1esGxyyfRka2pRlAtMZopE67FJNPBax6aDb7t3Tp40D3FqwBrnPkLvNpEpjadhQJLLGbUZ1ZVau7pWleXvys3qtdfdlpt3SRU3GxhleT5RyWyb6H7xliffBBWs6e2+EPrg","layer_level":2},{"id":"d645182f-1eaa-4439-854c-0437806ceebb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"PDF报告系统","description":"pdf-reporting-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/services/citation.py,frontend/app/(dashboard)/dashboard/reports/page.tsx","gmt_create":"2026-04-24T11:07:20.621291+08:00","gmt_modified":"2026-04-24T11:08:42.188151+08:00","raw_data":"WikiEncrypted:JtXUgB2EREv7ncJ+MegCx6wn6P3rv/DbcpMX2oD3DhY8Q8TNEnThfOLhKKIJTZNfzlKgubFFqtmmSTVW7QSMR71tLjgZgSLACwoE6wo1/FhEifj/8lOp77v9Aa5u7WO+EgtLVWSz4kKO750z4owTufvhVR+uZ2ahVoHSKD9mXo4KuqrWwFr60hm65igoFdhy/Y+hyNsaJejQJMCUwntWiPiJoBxyTIgf/GpbNj3Ed3Rz67bKvr4/rnGpjDMYKrLKqH5QhLo8wpIaf7MZcfqc6GYtYhyLXCLk61wnw7Xgs08=","layer_level":2},{"id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"后端系统架构","description":"backend-architecture","prompt":"为GEO后端系统创建全面的架构文档。详细描述基于FastAPI的后端架构设计,包括应用配置、中间件设置、路由组织和生命周期管理。解释数据库连接、ORM配置和异步处理机制。文档化认证系统的实现,包括JWT令牌管理、权限控制和用户会话处理。说明API接口设计原则、错误处理机制和响应格式规范。包含系统监控、日志记录和性能优化策略。提供架构决策的技术背景和权衡考虑。","order":2,"progress_status":"completed","dependent_files":"backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/services/auth.py,backend/app/services/subscription.py,backend/app/services/admin.py,backend/app/services/citation.py,backend/app/main.py,backend/app/database.py,backend/app/config.py,backend/app/api/,backend/app/models/,backend/app/workers/","gmt_create":"2026-04-22T18:56:47.08233+08:00","gmt_modified":"2026-04-24T10:58:51.176465+08:00","raw_data":"WikiEncrypted:7Nn1MUEMCjrO9aPSED6FHT454wxodEJExHk1Z3tdkRG7psPg9iIsEKvTk2vItDaJAXIG4d4xq8Laz0GUpWi7tvVyLa03YCfOyluItzeFyggOAAnOECGGCu8+eZnrHGjCrLMORlQ+1wEw9nkOpcZHrAs9OhT91iKgU5h0B74rt6WjaJ6MNzH84B64xYyEqmHM0niEHypbMjA8WO+d7J7BmhjgtxWBkUJMprVu/3XnDqSwD4nrvstGxDp6a2Me/1xldqPAIH33Bh7jHl8jwBH57j5llwy6peK7Pcn56nd6/IUHuPpwTrnoc5YduJIMKWGYxu1xF9PNaWMAkurHhHCoMemJuTlpc4HVN6jdvDHV1XLd1WD+tWrKhA2iqcmzuvaGu9XkVGmdF9XSUr3QcpLHFeBkTanbvFYTANI7G07mjpGtPOIvGgmHilbbqh883xvi0eQEyrXDdoAqA5jU+paPRtXoLxib8JBQEqB+fcKcniH+C74h9BHKdauZgcLRT46tYmeFNQiyrNO1vcm7emWe5DFtjbfwrxYUv0K5IY6AUMUzoATIs+eb7f/Y0X4T56LR9E2aUyeViaWeVtnLMiXVSgRMz1/fAG0OfZ1BYXRB08PvPctEfVdY3C2FC9+10XmkN/9fasMBvjcmO9WvIqX6eguoLy23soTupv+OrVuoZ6hiCfInpOcYV2r/ApKBP60ayqitCwvs+ndNATQGz2v3VVvoolt8ZIZvqhvzyOE4JAltTznL18weTTPLWlFYhCPnG3qPm4/bDu07klIkZYx7sKLgTJk+q9nrNphi7sFpmzfC6wnhOtCPR6moX9vrKxydsmZt9cgBuSBia2j8lOQuW4fB5z4WqWJ77Tt1H5EjT5vr3XU4FH20+0eYQYPZNXm52VxrLvB9embAi+nRLiJ1efhYYT/43T4PaUpLTjNMd+g9dYZAgDJ0SVX05PLYNgf0hrDicYjtZkb1/nYUORVOB1zsV5Vlxd64mw1OyQeTokBZYMIKVwfz5UppkEO0an24PaWXjGBnGwjQuDU+aQcm41Tzj+RpNOs5Jgj4MNTv/O+qBC2nvJ+HzTDKmL3LiAV7NfixyGTkrgW8UwAIlDIoPw9OhoM0cQUt7ngzx0vqevePxkh+zyEVs5vjLNwy/sC/UnJpsSsSAlFZ2knnjVE7Og7MI9qWikoCxEYO0qe0Rs33TTI4BlWyFvy4ts/7qO5lG7mkLjHXKv9351kbCuJfG0L4w/Pe7iuve16Nb4unvEKDxYCa+6CzFAjLIsZa4BdOQRsVxyUXf9P4rokWxV5I9sV4jt+WMARYpD5jvN8S2SOqqH6mgcz6Avyd7Ae/46d8Fwo1fLqt+vaQ8zAN+1W6NxUD3NRJqtbcG74m4zp77sPb+jKwNzpnAEewLzpcefAjyBDM9G0IQkgIucrvTCPUr0dK6NCS1H5VIGRNHT936f5C7AFiKxngxFR+EPtBbl3+5AB6y/yxA6jOwcyP22+d/rGsqnkMfxru4kZXc+SJWu6y5nLjRGUBJDZuECrt9WAGscutosi+ugvzvbZwXU8Ws3Ld2j11PJ2MFiPdItEBwKaK1uaEtnFGebbA+g4v2w79ingJODsBC/sZU9N9nFi37WgPpulaDGOkX/9hIyA61F1KNe0Qj5ACKj+VZUN9BdhIk6DNHWMVTRqAvdbP6aXn5Xe9uIJ2hmLtxltTcZMh/YQxM+FUEN02HPI9R2mkP5qg"},{"id":"159f2ccf-71b7-4d1b-a4c4-c15b23a4126e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API接口设计","description":"api-design","prompt":"为GEO API接口设计创建详细的规范文档。解释RESTful API设计原则和路由组织结构,包括URL命名规范、HTTP方法使用和状态码标准。详细说明API版本控制策略和路由前缀管理。文档化请求和响应数据模型,包括Pydantic模型定义、字段验证和序列化规则。解释错误处理机制,包括异常类型分类、错误响应格式和HTTP状态码映射。说明API文档生成和测试策略。包含认证和授权在API层的实现,包括权限检查和访问控制。提供API使用示例和最佳实践指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":2,"progress_status":"completed","dependent_files":"backend/app/api/auth.py,backend/app/api/queries.py,backend/app/api/citations.py,backend/app/api/reports.py","gmt_create":"2026-04-22T18:57:02.317509+08:00","gmt_modified":"2026-04-22T19:15:14.078939+08:00","raw_data":"WikiEncrypted:xKp6XrvgQ6yDy/qZb6DBAyzRhY9oY9wND++XWs8abaIu3G2LITgI+Z0UQBWYGKhuTqBsuTOr5OLyKixlekyR1Xfq7usrLYQyUqykz50fvTC/eHiVp24qJjGIE/yM/QXCeZCQ0Io9avqxwyMLsy7oz+0kRVW2WjLzRO6OrvbiUY+8yPMkSPi3UCtyM0GVLTpD/1yhEPFlJimDIuMsn1U/6MxjS0vcd+yEDjCBtrAoR40VIxrMz5v+dKD/pjfzoR1p6GEjf7b6zpzZGPhEtFmhzIahThZIdAaGShFz2YepbNwjns9s+2XJPvMdDYb5mBTcQCjoCHeUfqpQ5eRpjJ47qGFAfFw7lpv7GfOixRgEasUkVhJaX2fS+R0bGg3mmJFfg8tK9XXCm0OvNdgj+aJ6EUKT7GWXDkWLJd4NWEHKvqO9jfXu7YBJxM5tfR1i4e7CPz16fSaCPJtKsI+HgIoTf1JQ+3TrBqGncHko/5j2BznPg08EvIvKnECTrZEH1ATf3+Dpz7cY5x5f+D+oBDxG88V899fkfZSrXbY4YZJnhO691mRZPnKUgr3TsGO4kK0/eZw19HvuCyKxuqWlpHvV2nWGiFCyQpLul9lskV53bxNE6LCdF4LpQgsnxp3NRkXRo9kqVcTFEVZX1D65nknWMQHMOr91wEbFu5y7eHBY/M1mlvT+FpX/uzM6NvEAUkyKHsIpLihbh/obM0dUOwFr/y/hUOLfs5gw3aMosXT7+uwJRXkzxJlNzCyzWUQoMQbw19Mq53uhogOLGeVQNV9+lYZlsF9DEbUg7pWX1HOTZw0qj0G50JKHtiM0mGIwmRxZy7HDNhqrMGXboadds7LRAL8up6y1uZya4V4Y43X61XVoJJrERnU6caJROOJ+2I5yEbNYOvo/g+dDZf6DLrj/5IPInHUF/rwxMPX3V17obui48Yk9OOgLp3s7TEAU+t97lkEPo58h2oDARfsbxrnrVd0I9z2/IJSBouFoAA5+wGUVU3BH0Wdc9bwTyjJg6t+iiz5Z14RRB6hnBI45qD3U9a5fIJ1mWWGl2mBaOfvJck5hTbq7v+Au4iOMprm6m9SIq8C9D5w/PtHslYGeBDUYeIOWciDfxj90/WlNjcdIpE8qX8PqRFKdnwDCBOD0xewCH5Cw+MxNEuc6RRDsFu6vhFjjYe/vtb6bNc674kCJn5eQOGFAo6+v5wfkkZhG1S1q5EY8GJf+H3HgtucPikTjpKAbpBkkiorIBJ4n6Gdi9Jof2lYe1Ina6yJPsnNyd1MyQgdpEg7sStrvevt6IaMoeIe0vQ+WPecPhqsIm9X4wS4nI7Knd7q8WUsBQfphwlTzUb0igehWxKagmMc8N3x64Q==","layer_level":1},{"id":"9cc59a5a-f597-4707-b994-b6c49514d553","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"页面组件设计","description":"page-components","prompt":"创建页面组件设计的综合文档。详细说明仪表板、查询管理、引用数据、报告导出和设置页面的组件结构和实现。文档化页面布局设计、导航结构和用户体验流程。解释页面级数据获取策略、状态管理和错误边界处理。说明页面间的导航逻辑、路由参数传递和页面生命周期管理。包含页面性能优化、懒加载策略和SEO配置。提供页面组件的开发规范和最佳实践。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":2,"progress_status":"completed","dependent_files":"frontend/app/(dashboard)/dashboard/page.tsx,frontend/app/(dashboard)/dashboard/queries/page.tsx,frontend/app/(dashboard)/dashboard/citations/page.tsx,frontend/app/(dashboard)/dashboard/reports/page.tsx,frontend/app/(dashboard)/queries/page.tsx,frontend/app/(dashboard)/citations/page.tsx,frontend/app/(dashboard)/reports/page.tsx,frontend/app/(dashboard)/settings/page.tsx,frontend/app/(auth)/login/page.tsx,frontend/app/(auth)/register/page.tsx","gmt_create":"2026-04-22T18:57:04.216604+08:00","gmt_modified":"2026-04-23T15:19:43.818179+08:00","raw_data":"WikiEncrypted:5oI5y1yTFbg14yVSXHYDGFeITEbIkjmdES7qr/P4na8TrPHqKZDCV0OwvONxgczey0MsZEE95T/q1IqTn1MDXDe+zweBCSZSlefgNsHwrtPEnyqFrV2NhO5nKlcD6tYwGnW5Ag8vX/svtjfAjl//gRYZD89hOQGnlYrcSU5a6FC1LQaaD4KqNgrn7yYxshfLveO4k610B0mb5BrOdyTpLLBcuNmEgY9/GKvdoyt0cfpZPwN5J+wPoYjAnGjm9LDIkL9L02r9Lvvq1mhN88A7yKU49c6lU6S75IzcT+OFjTd7OXXastuPBLJRb1A0sFMKjZVshweginUNg6fhc3vFQ08Hthoizv1Pjm4qNnloa7P3w/rnuQrvCJk3Nt1PWn+ouHeenTb9bsV/KwF6BGJ4HGDSDyFcd0YmY4CDfW5aSBFP1QYneJUBxux4dxgw1GbBsa6R2o+cDCB4DqSA14RqNvsI4r16PlAraoYSaQRYj8NQzY5dRbzpEnhmyPsBmgzcW1gLo067XcLiF0DJvlouezCyJW+Y9YA0fmJslQSYvcMhcI8mYdAfGDi1EoXoUiQYMnvlYq8J8ktBwLbIskG3FgeWvmoAFZE08E9APByPtLjDcHHan03Nwy7CPZqb6FtXLeHH6H4TK+WRnxyWWUCCGwQxVYXq0SDxaUvHuhZ4XUr7+Q1U42rlW6cND/0kiOhqZxe5qp/7PBom2IrcPdORh4lVv3RCQrIDCkHcBzCV+1WIwFeaxUaSDNJMmZ500JhDl+ECx+6dgbMAMTRPh+SxHxLd/OJMI9dD9eWQZMj4RwDxTbqlVp8cpoAEGPNvmweo2JApNndlNo1gDMJ++de+I8cKsyCdEsPfQ8ikJHY3R/UaPh/mPp8pQaKIBBP/nvMsT8jYMtdv59ejwQy6+/9dplr/mqdQCkRA4B/maZQ57aFmnsw8HZM9ukvo0Ni9KpUFM7iFAVdZy3NGVf8DX4J0jwAjd643HXH9I6+6dP2Jfs7ezsKz1T5yAHvocFPqxtbC3b6WrwrjPWf32N1a/qM1RiZdPyUNGE5ij+CTm9PUzcQxUcatfkjdDGnwRIAJMmmrtYVTBvCP+xUKuAp2UmXU9xfTYxlU6rdp5LyGQS9dHP0x7KBg+yOWNzECNEzMiCgE7gOqv+X75WA7D/sSBMaO52H6f4qtJovvnkwq4r67A/ByroGz4ctZ/wSVqTHti+gzlXIxgHKWr8VVq1HUFUCSRdZH3Q8PaR08vmQcapIQHpDRW13nUf7saKZh3N6R63lREJu04Ie+fQ8i7VUsNE4QclcrUsdj7eUxv5xtz7xrCEBDZooPT3RW8OM08MJ2Qe9sU6bdCvHTPE21OkEYFD1tWzWH7149QZPhOzkXIQ7qGdKQlmRvyOnd4uL20k58I3p/q9ktqLxBCy5s9Ac6PYODpXPLAelkYzhV3TcJAzxphaGjCmR8goNGJJWsqw3FOOCjGqWliL0JmW23Xo4emXDMUU50N9Ru8dM6NBIs6o8Hy3YcM2dj4t5RwlVejQhCn9gwtm742VYEdCEYKq+8FJtp49Xm01KPOtgTyFN0lF+HOQG6LCrIBY8cXRQtkck1aTvxD+KmKoVxp09guujaDutV+eyhyb5dYSytjq2ptL1FsYHLS14Xa+GW6DEvniGGnCzP2LTzntbqIVzx3J6F7gquTfsiDTTPkIijyYxWvkSseJc=","layer_level":1},{"id":"f70f5d9b-d7c7-4dc6-b36a-5f4508e6acaa","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"系统架构","description":"system-architecture","prompt":"为GEO项目创建系统架构文档。描述整体的分层架构设计,包括表现层(Next.js前端)、业务逻辑层(FastAPI后端)、数据访问层(SQLAlchemy ORM)和基础设施层(Docker容器)。详细说明核心组件之间的交互关系,如前端通过API与后端通信、后端通过工作器调用AI平台、数据库存储业务数据等。解释数据流向和处理流程,从用户请求到AI平台查询再到结果返回的完整链路。介绍关键的设计模式,如适配器模式用于AI平台集成、依赖注入用于服务管理等。提供系统拓扑图和组件关系图,帮助开发者理解系统的整体结构和各部分职责。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":2,"progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/database.py,docker-compose.yml,backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:13.329904+08:00","gmt_modified":"2026-04-22T19:15:17.452724+08:00","raw_data":"WikiEncrypted:gWB8HBj+8+/15rQhXgtMjCy7qJxJBEw3w9EAqc5Otte14+SfcEK3DSbmZRhW2TgD6BlsxDXHpLcSijck/Nymh09xxwlFe9hXY5fsIsj1IZW9egIbof/vmRQ/HkxJSvNy7WDeHEuuU7TDae+7kls5UELL0/oUUiCC4fjizzoaOlqMuOvW/DImO8fA0xbQ2wAt6L3bqB1pcGWvnB10d6EKKhQYmUj8xv/2M3cUBtDMkUdyKbAuduBIInt+jZnOGnXKcr1w3W66u8elz0iqgWhMCsMFd54QokMhn1Uyguz3NcIfEVH6IlKil0ufINdb2d/QV+9aukLvJ4Mq4YDlUjQ2iJ8oxAYYUb8eIjBnsLHPfBnMUyXVAo0tbyNB7wUmRb/L1VR7ipOMMKd9mEohzKGpsTxHpM8my7x8Ryc9N1guO/H766qiiNij1HNCu4rWVW12oeTTjAoEKdLzLyn59Fc4QjYVkS/I+r/lwRtMNN0OGjWXGXea+HUaIHwW1088PW3eZj3FlyGEsTiYb6ysJAWanY2qoIhASm31o8s9DekhdxTRbWeBCNzGN2ufTYGM9ygKNDHF5dCbVW0/Vtc6FC/TDiflhIaDY44Gvuu84O4l7SRBl0jKM8uCFHOgx/NzDlnUdNFaSOdjUBxQ7vVyi0Q5X6P4H/ERPzJQvOa0gmXW7S1ry0P4/CRjOCzq0Afw+mAf2j4PHM/4MWFkvrFkycbEkHWoWnPY+DWYI00TVSdTWjj4n4l9wbj1XDhXavLdg00qHVjv0dTq1ghcZKv3C04T5MfvVQjMXCKPQaK0KzwZDfXydWnlyLPgM8t95lTETMkjjEpIMtiv2w1gJda4ChFrJq27oPmVlEoVzGPuuk2B4YN3z6A5y3ehJpejis1/EuBjd0vXHhwghZeUv8mMD4smRPUMA8GcEeKVs9TQgBHqVuuVDdEAQfE7w1ILarmq3trYAuc+LH1KMUyPD0aZEbhKZdMRkFYWLhfyYeuazm9SfO1BqtEuTVoAXdLD86TCQNmxxTZPgU9OB9JluopAMt1oszBwKK/88UqwBqgUZle95RTKVR6QPn7zAGZaDbfsbYvsGUfNBSH08o6nnraxB0Vpj+r6WaoZLCcxhqSWoTp60YlMt7BDsla0Lt8r6D+a89AtCqZOHLJbrEx6T4wsmiykEi1uC/9XhtcsTHuytq/rHeDWR/bTToB+mGjBipoGscvIFMgUJonYCOjLDyBPGpeWispYZV21bIJQtFIYv06NKYU/IV9ZISLel9AttowTEXv/Y/U1xRtmaTp3BgGI4iRdwXYMJICv7Jyr5kYd2CrLJQPzEBdkJi7+q3WNdTCWBPd3B3hL/tTL2lFNDOc1sqMga78PcdWWHQfheORW9OfH3cDRiq85LJziojysfwkQVqHY7niPkDyphAwn9F2xZZl9ZfahAaU07CgK26wyavgkYOAU0dlWI6WrAKE2gQOzOxBL","layer_level":1},{"id":"816a2805-76c9-4f32-a3cf-96428208081e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据模型","description":"data-models","prompt":"创建GEO项目数据模型文档。详细说明SQLAlchemy ORM模型的实现,包括模型类定义、字段映射和关系配置。文档化每个模型的属性、方法和业务逻辑。解释模型之间的关系映射,包括级联操作和外键约束。说明模型的序列化、反序列化和数据验证机制。包含模型的生命周期管理、事件钩子和自定义行为。提供模型使用示例和最佳实践指南。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":2,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py,backend/app/models/__init__.py","gmt_create":"2026-04-22T18:57:14.161024+08:00","gmt_modified":"2026-04-23T15:21:46.785144+08:00","raw_data":"WikiEncrypted:Zb5TNaG1u/mRrgPr+sDyCr47uD+4y/GruMCqF9C9nxStxKZi2OWvk4ViC2NJmWUO/Jxugi7iel+AeINiHAz9c7erlmOh78DEPvZI5zcQaIYzm9l0e6yLGbMS64gON4GYqx4TUizeLGAIntFG405vTATENZMylmwR0jTbWx2uP/KlAPch72o8TGREvPTy7FGikY773VIwNZq0MXKYxjbwvld1ADWYjtxMoKmZ7pixx5LeZM3O+bfisD7UTqLobS2VvR5Ic2ynsAkEEzef+Rh5O85TXra/uluSuAOST9W65TENzfEzwHe+CNAQmUp47/vG6d7I14WPEipc0/aKbh43AhJkclnRjpR0bYFPJrW/HuN6chk1uhxzBK9sKpOUOLZ5MffdIttkTAOz4Ny5MxnUwt0zj4hDsVOevpasy4FZ/3pVx07fb7SlIDC18p+OUYQIk9JqBxZmgeMslhOBSkmRTAwqir6PN/GuLEeeC0mPlAMNhsvDrklfLlJmLY8MuSQHqteqYJryoZ1cp1yeqxATnDfeigUr8eSSaFqZc5S/AlgSIrvr+7XJWk/Oz0wKPLRXNUcG9yDweys2pdDb/hV5hiTmLYjgvYvnDLMMjrFgR6Fogz3U5ItD0xLC3lt09GJfm8jhS9E4AJd36iPN2WMeHsM0ctdvzYB/MKtWIIrBkWuRD7CZeGJepiGO/GJprp9HK9m+APjZQ4oc5d43tgDModdepglAEgNklY7IzUAPW0Qls3DhfUUHq/Zuf5AxAfUAAg1JOW2qEQWV+btkeoRPEiHjZXFDLGsC226d9yUlnYcTkFOeVbL2gomt13MPt6c4EQ3y4BSoG1CYqO0q6IgkX6a4g9QE7OKjdE3RX8rNGixxNJzfx3oeGtcne/lDvhO9/U5SlpNgbkkemAIPu+eZw1zMpknFdRwUdwOwgyVNxR/tt9AEktJ2gcaxRGfG3xTSa0JHoniO9otA8VI+Paw/il8qAI4Z1kf2w+L8LavGt05hchhlzWcrGbBjXF/VkCoYxFvM6JX9FafcLjoT3FtVTSorVysHodJyR1nHB1TL6/SH9v5IZMlZeQ6/Gm87g4SquVaVgvEBMuFPA6c7BBhWUqGw48UIBxfB3Ri4l8HYfRBiqrPSIuldaD+xTVL8F5XsVhczS4JXDnX3RLtvjOuBZRcejVO0ubg+syCfBhf+6CtYOyDTTQDGgwdiNg0MjJnmjy5TMmMdynOGSm2oF6wS+tUuWG8lMMBtredaLHdyVb455+OY2oQ5hJZGo7eyzchNabr+Xous+Ve/4cM2FOoHdQ==","layer_level":1},{"id":"64cbb894-755f-47b5-854e-c26c7821e9b2","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"文心平台集成","description":"wenxin-platform-integration","prompt":"创建文心平台集成的详细文档。详细说明文心平台适配器的实现,包括API调用封装和HTTP请求处理。文档化请求参数构建,包括关键词处理、请求头设置和认证机制。解释响应解析逻辑,包括JSON数据提取、错误码处理和异常情况处理。说明配置管理机制,包括API密钥管理、请求超时设置和重试配置。提供文心平台API调用的具体示例和错误处理方案。包含安全注意事项和最佳实践建议。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:14.59287+08:00","gmt_modified":"2026-04-23T20:31:50.506814+08:00","raw_data":"WikiEncrypted:2Sm2Oxxfu6PsmMr2pZflRJ0uQ9gYQuPnIUHmJotOVM3YPmWq0HSDTQGvIE8WdDGtHlaemWXQzS6Ra6mdo6lkRL4Slh8EfpKUg4wigWPN0r3GaSXHkkAIs0wgET5OjWqYvTL1QooFFzxPhX1ZTdHcTpcp7CVvRNSVGiTu93qzZloeLF1EwOxsLvQ8hFf9SuWGjeOUYDGh7ktNwrMbeUIV32VkQlqsqQ1HqoKoqjAh2d6Xou7+peaCdxzJOhMf14e/vNiC12p6PfM2oyBY8gR9sMPKd1zgEepWsc+ePSazz3RO+zy9fbc5pJTLZdtswhL0xGhZKuYgYlctRId70DLeyiJHlvEQzEE8KB7QJqULfiB4lgMO84A+DhPeslR4F9Edbm+5P11/ycz4y8kzZQwnt5F4iIOC7HOPRSdGTYTxO53cEcqSfBI/wH7enb6Zt49h8mK4UyYW0fUuKBE7dPAjxC6IxbdabWdu8WefhxUR1oFx6BkdGWLLmj9ZOLMReTwnsJdK5xmoA8wQvV8MMlYiCgBuPj7mYce5s5hpglFxtJdEeDq6P2Mtusvj9uegGeFmCJSn1nbBhJr2r+WxLk/WpDO5lwhggW6V/wdvqcmRvaGHCFspVdzbC2qx104c8i+2wum6kMLHVTGAM9kTy4M5vHtvBELFl/qfldVQ8BK9hUvE9jdUbNQkoiBwFpPt2NNFYvz94CAxqbObxiZ7C1VhKWPH2AMX330wwjiHjh0eshve8e+pjBsDeM4/nTh3PH0P2XNUsomNEDxCQpXG7qngeiMXljTWmyGsLk56SzHFqfCgQX8fLlxv3PzSHXpCkAdymDxnJlcuK6WZIMj0AjQydGVSLgItD0boSI0YfvyDXhrO57OoFuwUU5Enq0do/w+quy8Qt0Qc9Q0afMg0GVUksiDfURVugssB75pqSqdNSrJy3wxM+kSBndgaiKYIakZ1idHkzpiGUshjyAr3V8/N1vW7VGyY2wnoquEclltaRAO6V+O8ymywFWL+/RrPEn4DKy8ul6EmHuryCQh1dfEPk5ZAgYg1K9ecbb2dLwTfMgXIhD/ar0ZfRO5OdwADW376","layer_level":1},{"id":"412f8cb5-54c1-4f32-8966-fa0e5e75bbca","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"性能优化","description":"performance-optimization","prompt":"创建性能优化的详细文档。解释调度系统的性能瓶颈识别和优化策略,包括并发控制、资源管理和内存优化。详细说明异步任务的并发限制、数据库连接池配置和事件循环优化。文档化调度频率调优、批量处理策略和缓存机制。提供性能监控指标、基准测试方法和性能分析工具使用指南。包含实际的性能优化案例、配置参数调整和故障排查技巧。说明如何在高负载情况下保持系统的稳定性和响应性。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:25.383759+08:00","gmt_modified":"2026-04-22T19:16:37.81704+08:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3Wm3Q7klXxmeD+JMMoGiSO2oNryWBo1gw9kLkawvxQIW9CASZSiyAjiA/zeT5DwD4S8PDqEsVNE73i6DrCAWvPET3MMPQasVfJTaLge2tk6gbYlx3R6JKZcUoi06jS7okoLDzJAFru3F6zguqySliKZSG/00oFVcDHXlZZc0L7hiq11k1jOD8uBl6n35lAvst/AgFv9MUzrhf43XDwtHiMAxjCAkwKnrWOow44Lwzy5fG3nWKZLSHE3/CUmZ17U3GmEqfG43ai1yloAkMou+sTRIk73sRdXPDze0HhNdNfNXTaOHTxW0gT2TwKGHgG9Jt0Y+1qWq4Nxj/oJTP/hztBLy5SEPndXXqeZTkBaesRTr0adQv49fH0QoFV6D6dxlEOodMiFhvvYd1rvR+HwbQbqU3W5UDVnKfPlMXHsz0a9NPu4aGgk5yevh/s0AP/v2R8mgz3N41lETHxk6Q71f35L04S7u7P6MlorIwKzkeijhFf8sPrChMYX7dwf8dWba+Nwm6fgb+9AbSZ4VczhQInnbiv+GUKiFnezNVSHUUXqTCvRIuhF52jqnOqjPei/1oeS7xAMmB67o3v2so8T17xg94F9FoEl2XuuwA+RFDarVZKACDTPxjt70OXdAoxoERTZ3ivU93OANsuuWx1x0HgFdBj0q6seNC8cbySc3ZuQBWGu1YWMmyIYGL5l6L7CNSmkkl9/pkb1TSfkyM+Hk3VLXy8VIvtgHxGX2OU8yX1nX0DCGS9Yt3dK17lAVH2XF2mo39noQPG2nxjOc+lO/O9cL/CC1Bqzd51YLHapcRLPPbuaMT4ljyLvQ3GMvKHB6c0sjdaKjykN96LhXpO5PAqs3N2edkVKVMC6lg5fTBMZi6B8r4rup3M9CPDs4ehmVYTtnZpt5zKxyXP8QfTO1FfDyNQRpbXj8TyLOwwqEFvZPQlV7Iupj3lpi6crQhtpXBtU9M+vjP31rOrdFpBHXCckE4T9QryVWvQuNDjsc1+tYKLgF6S8ixDQFCHEAfzctdMM3iiLCeBy1szBZEZTE+OS0ERSbgqusmZBkz3ouKp6suUgXLJp3Kystu+dAVWhA6BAD2WHT76h+Hbazixj8F2qAoxmUb+P8Z7u0grbWJksg6u","layer_level":1},{"id":"40ac97e8-7ef0-4198-82d7-d2e332be9d34","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"测试最佳实践","description":"test-best-practices","prompt":"创建GEO项目测试最佳实践的指导文档。详细说明测试代码的编写规范,包括命名约定、测试结构和注释标准。文档化测试覆盖率的要求和测量方法,包括行覆盖率、分支覆盖率和功能覆盖率。说明持续集成配置,包括GitHub Actions或类似CI/CD工具的设置。提供测试调试技巧,包括pytest调试选项、日志配置和错误排查方法。包含测试环境管理、测试数据管理和测试报告生成的实践指南。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","order":2,"progress_status":"completed","dependent_files":"tests/conftest.py,.pytest_cache/,backend/app/config.py","gmt_create":"2026-04-22T18:57:25.616954+08:00","gmt_modified":"2026-04-22T19:17:48.81542+08:00","raw_data":"WikiEncrypted:3lrOgsvw7LaJXRS/Bz00iEsb4RzJUAxxpmqaBblS/51b52WVRQtf4YGBQ9MC2MYcYNyKxRGZljd03HKmm078aoRU+suxjG3HIqwkvM6ruyPxwlLdBEn6ogbrhm8eOKuGWjiEso+PrOqSXW0boT4qGE+/L4MkPiyeOB9YnDB49/ByvDHsjeesTQqGwpa9FmIQtVqpqDZA3Sx+x8TB+MSqT5PMZ4egRgCW1ODcidZrTriWvseFNQDFLzo8g2H/HF5CFLcVsZVK+kWI7b7oWLmNlIKz2SyVJuYqvCblPzw+/773Wv4RVHYdK/pxISCon/L1KjPyfZjddr5sDjJO7rNFbBshPxUIQhtXnnAEqLOpzZwHm2a0bA3vSR42bZZoSAY0v3aZxXQ5IvxNT/aNAmiFzd4SkTlz0okDXnBsArnOUpLLRfjLhxt5ueRUi9Dl2edsdycd6XznT6/oAUHTf05zhhKC6JR1OsKiFQyoo0il7LYjDxXJM0dZycDlENYwZ3Bd/82Qr+7VNmgpLdnB/7z9DPG9iou6TIpztKrdSRYqWBcl75qs2L/R2Sy6MOyfSwALTRUi5udf8sNlsHOk5y2qY0h7vd1GzYwtxKQ63ypJLL/8fAcPKmH3FCwKvrN3zuEu0Meyq+y2v8eYeXNozeOa2zum6fI5sw7hnzX9Jqy7fyQD2yBFqyylQ1ZW3nwFd9liZLnWfm7zbLDlqSgzGYGxvNIe0X2rhwsthMZTLEXOZVDW1/NqHg2E9qXOfg7XhQRHKZz6Wu8eZ6MGyCvq6ft2SJI2vltHD0M4somneHGSMo4jKY8rMeGl7qkW1V7aaurBnh0xp6cOJ25IdbN4VEDYm1Oj5nlM4wnEQzWiVyEqA+3oU2k2k9Plm/xs6g846/lBJxHL9ztsKmm0BnrUFR1ttgTVRAFvHpfkmSgLGGB/9824DJpxXMiWnExCaZzWbFYPhXnDF6Kh3SB6P3NyVwVdC9/pkf4/UQ4Em3rvbVuWICjGSScoDtOu5MrHDaUSbtN/XtqOptA1ApGbnTSKxOm0KAck4ApFPdk6aRLdC4eRf9XWsWUaOFjkqAoU0Kp035pHaGrCrx4KmgoKBNFNbS55CA==","layer_level":1},{"id":"41a414d2-e13a-497c-8a03-212624dbf5fe","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用数据接口","description":"citations-api","prompt":"创建引用数据查询和分析的完整API文档。详细记录引用数据的查询接口、统计分析功能和上下文提取机制。说明引用检测结果的数据结构、置信度评分和品牌识别算法。文档化引用趋势分析、平台对比和竞争品牌识别的API端点。包含数据过滤、排序和分页查询的参数说明。提供引用数据可视化和报告生成功能的接口使用指南。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":2,"progress_status":"completed","dependent_files":"backend/app/api/citations.py,backend/app/schemas/citation.py,backend/app/models/citation_record.py","gmt_create":"2026-04-22T18:57:37.836961+08:00","gmt_modified":"2026-04-22T19:18:18.055339+08:00","raw_data":"WikiEncrypted:qByx+WzXalKNnda2aYUs+Mi+kQm14b3+m7dy1helFRbYWzECOnPEzHl0ufCZlQvKjQqSxHIwqppPXSdvXYc/8Z7buvJqBV/Q/faiP/SBsAH3RrfF2Ppti6QanNvcAtBLcojqJkmfYWFej1OYdagzBcSAu0xIIA7qBG1LwkdNG8crxSwebM8is42SnI+aRvlbF4UdAqHHPdfUvnzs7zIODnildIoR60AvLFeNEWO4prQkFyS16p1YH96SousrFgBu2YZZYrNOOhDXyrRoW3TE6990oaIi3Xe0B7jFtC4pce8JamwzT8B33FAJ6utCOBMUkFKq6l0kD5rN2owZaBtGc4Q66Xcb62y3arqrvxcgE1ox1nAp2D9pNqRy3W1ePW2fWZk4+3co4z2+ANQ1JO8q5eAFI6Q6zG7hM4rvNlL07iD+hZeqd5+vGw0KmjkN4VMqJC5ypFf5UCF4qHgB6TS9ToQUAWk6HWlwBR1DVpCcK1kyGcunn6EiivJyjJLRYUXI66AmajxIzRHtyhxBnA5Q4hZNgr40jHMoUbWHmiQTQr7Ca4/VDS2V5FWlm6K1fN8xWRIUCI3VtH0A/wG+QBnJmF5YeqDZ37Nx9vkiaO+hutXsGHsjwj8+IZO/gpn6UT6QpOGaeqGl37HW+lMZSRUqFFaLg7jxlzSa3IliOyZI7N6xjFFFTrLV1ShVsDcWDg4eXL2IjJ7QfXjmD0vq5mH8mkZK6HbhpNH5kFXDuMYWPIHAXUk39ttNvut9r22RLpkXYWtxE7XoqXW+k+Edmt2eNvZImq/e7mUwa82Cae86WiRtz7B7TJeOf96EvN6EQBg8E8KT5Ckd1exHhFtySkw3tYfChBZfD75zY7tUcZcC+McO1Kf0ORqTZtnNjVnot7wirysiS6WKQ3O2L0CeBUUV7DlmFd8xAgJ8YhtHJKulJ2B0yCCswfb+PR6u9GKFVK1EcspZe5BsT22vlhQyAJxlqiAi9xRk+XaCWoUT5ymT+KMOXdLoB4EvD2ftgXy5GMxZIK2q1QtLAYEu7nOBsq2aNAg9i9IsVJ6OlCN7VMzDinzkoC1IAWKxKE67ZeLq/VfPmCqLKGl0z1JfkfC/kU8KFA==","layer_level":1},{"id":"2f7fa0ab-cd3d-4f45-a1c1-389d5a0c2561","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发工具","description":"development-tools","prompt":"创建GEO项目开发工具使用文档。详细说明IDE配置和推荐插件,包括VS Code配置、Python和TypeScript扩展。文档化调试工具的使用方法,包括断点调试、日志分析和性能分析。说明开发辅助工具,如API测试工具、数据库管理工具和Docker容器管理。提供命令行工具和脚本的使用指南。包含开发环境的优化配置和故障排查方法。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":2,"progress_status":"completed","dependent_files":"frontend/tsconfig.json,frontend/tailwind.config.ts,backend/requirements.txt,frontend/.eslintrc.json","gmt_create":"2026-04-22T18:57:39.374817+08:00","gmt_modified":"2026-04-22T19:17:43.353691+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9CzRj7niAsR4WPU/tuSJ2vBrZ49vjzLlsqusYQAR0/FVC/Mfa58hrglY/tUSn8LBYDGZlVr/UyLd9/U09SEPTjzLPzOXWOffceGYhaM8E9Cx6c+FHZRQ0fYUDQXxWM6dQF6WQbUmiZISlUpgtOkT5wX0oc/n1YeDUxEpgiCWnOdIBH6SDoRDdGUFrWdqF66bEdplp0Yy3VYVBKKwUy1XVXtLbdv1T5/0TVJO7EtkHdoheIwKCPIYHsaJqBv4U8cMNegSJ1Ti8bsgUakd6FM/X0ybfTay+IyTIqYXj/dS0tWMm22zjLqYmw59+s8gJ7AlgwXhqYhM5Ycwh/PNrDHHFbgQdt45DjAaMWjrjXrbIvM+kXuSiwxW0dEvQtouckPTVohVcRWEPbg2o02/8Y5DzmxpceOC7KgybfaaCQeJHbg9C91itVc+0NvorhivJt105EYs1ndSOla9hoFppywKIbIM61cvqgHjsJF5DrN1pneGmTtYxijl3J/QpJHn5QuIBR8ugoHdJ3EVjUR38vQReVBeDxI/VMe8k/l3EI/Zk7paXexGeTrJmmnZI1I6WbPN1TPS4nLFZWwkA5ZA7wMkdHiHdnt/FZGccFyq8X9Okog2xv6uqH6Kwz3hseWlrSygNPzDr0cFj2EQqDH7+xZDEkAvTuFLHn+HzUfBv0vfZFa/FRg+5/agC9EcMHM+75jEvtSeeHXHOLpuuFcyOcZ0IQP99QdzSEsLaISCINs5SKkzKAMQnJv4PEDo/vFAKBulCSqjXmLeyhcKmCGqafN7IMWUWF5pmZuXe7wL1F6n+x3+RvScmsWND74hQhn0/Sn8kpFHJ5xV/5t0GDZxWybDFRRuFC8oImKyB+6h8CstsERuFeiIjMv2TS5lz8+eb1/yCUkGO9X5mUpJZXfZ+0vu2SkEN3WR92tM5Di/78rDlulwZ4oykT8NzYMTzpX4WlgUfazNKLyIhSoFZcWUyOFcU8IWCoOdrBFn5CSpe0VXbOlP3pAU1Lz6Y016JUHo1t1YE9xU/m7OTxhMexA8jCoSswgGT+Cjs9u+KP1ji2RSyZHQ6","layer_level":1},{"id":"2713d5c6-c6b0-4a38-83f6-56940c2bf695","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"监控与日志管理","description":"monitoring-logging","prompt":"创建GEO项目监控与日志管理的完整方案。说明应用健康检查的实现,包括服务可用性监控、响应时间监控和错误率统计。文档化日志收集和管理策略,包括结构化日志格式、日志轮转和存储策略。详细解释错误追踪机制,包括异常捕获、堆栈跟踪和告警通知。提供性能监控指标,包括CPU使用率、内存占用、数据库连接数和API响应时间。说明监控工具的选择和配置,如Prometheus、Grafana或云监控服务。包含日志分析和故障诊断的最佳实践。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":2,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/app/main.py,frontend/app/layout.tsx","gmt_create":"2026-04-22T18:57:40.355514+08:00","gmt_modified":"2026-04-22T19:18:41.773778+08:00","raw_data":"WikiEncrypted:HL3VqGjXq8A3aGeLxAjVPg+lnGgkT5PNghnzp51sgLDjuJwvzPZp6KDp64sXTqk/PvlUYRCEe6pgM8WKdtus6ThN6y8bzS650UmrWXRgW48k0tbm2PEPd8NIqpzEYwRwyuzLECVz8rV+mgvy+OHzvrt+wEQeT7z1uljirnxeLZWJjIrFBr8Q1T8WQ9InM3Ttnvm7OYO+YH2Mqi6IC38bW7w4WGqApS+Byn7/ZrJhR3B/XWh91FPwq0GRUJ9cqrNuIcYtnWAfVIHWOe3iET8Jw+Un5x7ZRepcJlINGIIMBE2hO7UsbC/K3z8rkz7mx6uoPTPpxkKkgoQQ1OAsShE/wpHpRYSOJEnV26GFo4bXBTk6xJYw7daKnJVIYDSqSrtJQI4yPlTR0OtJescXSLobznoVSBo+L+PU/nRvotp5KzX0SUpbkqNzGychqcBuJhpS1eaEP0cTBjvjC4MJ5Lsye51X6aOdYYC7tBWHxtgBO93tkpcIRlHk8Dfmzh8nKcD0rPHYGnaeFpzXgGH7ZfabAwxiMhej6OXWsfnbHGg4gheWhXfokxCMKkFnzrsYcuFtB0BqUeadjP5LArbJJGeyVEZovmPxtzQ5z/ayxJs+oyc0oH2SMXCFtIQv2h03ZSOCkohVRs2oTJnMI2p41dY59B5qiSOp+0qwxTWL9NnpqM2gjlLZhcgwF//R7ag4ndECWejInOcA9Ayvx6cPAuH6uEoFTcUOCLaOZ/u9T8890S5KHS7PcNM8dEewoFviz/mRiernAhd08l7a9lR6zck842Ywi5H8+fuuHyt64Pwco/+52MhD01pkK+HWSR0EqPc8URlkOKjQSW0jd8E/9ow54aZA0+1Vto3d+Lqi/tAOlhRF34rIJgTEN3f/udCEVycON9KNtssYzZVNPdvTkvzPYdUHIcnYmz3jbQhnYnrYvuaWNvO0cPISLZI9szxLP8IhmUc9xT4U3OvoRfFka8TABGicEUAF6vpH6H2rCqnWdBydaTpRTa3VAR7QJ+M0aPlzeKov93eljMa/djYoQo+w8Rm3A9vGmGXJKfWdZobh+fQgc38Z/0yRCHnIPnY8o6CDBfwbANfjDRpjyVkqWq1cuqYNnMul/jpzDS9vMSbMnefISRuF0kH8XS5C7pIB+WFn1vxeYFBYED7ZI4FD9pxxS6GWGcYOXEoFcqtR+lEiMdj0Q09jo1nEuMKJbPQre/RG08O0boFCzF9KOSnS0UA09/82vFQyQZKHNwpz7OkZZa2cX5X1L/pdsDlDRoIdp2lzyAEOidStaIWywEj11EYVNbG7sK562p96Sr15ueIXP0s=","layer_level":1},{"id":"c8a468af-2982-4d9c-82c0-313b5d2ee89c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"第三方集成","description":"third-party-integration","prompt":"创建GEO项目第三方集成的详细指南。说明新AI平台接入的完整流程,包括适配器接口实现、平台认证配置和查询逻辑适配。详细介绍新数据库支持的集成方法,包括SQLAlchemy模型扩展、迁移脚本编写和连接配置。文档化新认证方式的集成步骤,包括OAuth提供商配置、JWT令牌处理和权限系统扩展。提供插件系统的使用指南,包括插件注册机制、生命周期管理和错误处理。包含具体的集成示例和常见问题解决方案。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py,backend/app/services/auth.py","gmt_create":"2026-04-22T18:57:48.68499+08:00","gmt_modified":"2026-04-22T19:19:17.361215+08:00","raw_data":"WikiEncrypted:WxCGFGSl9zR6IDeUdkqKNACFcGLyx5HNn0UQzHtkOJVoVN2BLrMtPbbNkfhYYzEQGaeK3o4fBODff6YTXKxAV6HYhCHjmdXJqBaBsEPBB205lzDAllfBZL4/6ljz+/HZSgaWAxPECD1m2GUFvjlKHTSXEb0x5iVOg9R3VDjYQgKl1SF3S/AuJj7QBbGiwmkyPrqO8+NXDlKH7pI3G6me5ulZrK6M85KSH8nVAnqY/Mvjc6UGQJBwS1QyKJVzzK2JwKGhQSSLemxD887b22bSe7q1IEDRYcpqkbfyICB0zF1Gg1h/cAfQgzjiG0+MQiC5CF3QwkFteFbN4KZDEjCTcbIR+HqI+yCs8Wue/MwdoTYQQKpR9FyClONZn5T/UqHQaVT8SemYF0QC/kawyEZFH5Tkj/6RwS+taTWw1fx2QC69xQlW04ManahzsBDwfz2W4RkufM3ZfW8HAN7SorY7oYr1Vam2p2u/93jzHmi7PO/Y6VphQNACzUlfRYsPALVBkiqpN4TIiicrjOvhgATUxqpku2MrAtbXTkiuiiQBamK/XrF4JNlh+79VGoHKWniah1nvo+dzl7jll4j0woKwWKIzmfPXLS68HekW9h5BH9SUeuyAEW/pvnGAUw8Od3CgsEmap86k42Tg9pRZC/sT9bCWUbjO6ijJ9IPAgWE6bkLCu68L2BD1yKE3gfLg0hJmELn79lHaFCUc5jlRdJ4HEsalAFGS62beLGkude98NvSY5pQoO9jbTj3Da8t6Yj8p97WtE73vmWW9Pu/YyAtxJH7Cdwvv9mbvLYVnLzUWGwsaiaXmDJiqfSHiOrHQNyonHQa8N/LYrbB8qBSUmLyBUhgI1YfYMa+zNfCaeHvRLlmVZpui5MOegWen1Z61WhPc6WoFYHyFAdgS7k21cC9jVay3u87SjSzooFT3MJjN+yMIjrQ5U+tVFbiBQK7IGPLFHRmvFBrBwSFVBI5VnCxn4piz7VBp7mm3e6N3CJUKShQWQT9tmUIRXLmmzsKTit/kRAUrycFjixIK8Hm4kSwtVBREbX3opXE6clXKGVB0bpSDUzB8Ae7wOPE8Gqo/ewy3kh2mdNnvI3+MfOOgPc+Ovqu3KGFBH/MYKl2xIUGdYtEHfHRCIFFVVknX8+Q+tfbkmo/Tw+kJfq67IQO6VT1WjP/q1G3rOhp0Ah5h1wmxVfdIaHSUOT03yQTBm/tqCXlgUW7rZbTc2wF0zdUUWleQoq9pc14c0F2SNFCSaQNLhxvfeC2aH8O9nuZi+kVb+GVV4vWcxcz/7dfTkXpogDwy6uqVHySe/TAn04uWlCabYSrA3ahnl0VpBmalBU1dtaTG5apgcCJ9PULyHWKf+iW0vle9pOVgZQ4oUv0vXxDpZQkO1SOBCfKG20swUEItxbAxIVoMowR52maIRnCKh3g18NF3JUZX2ptDny7A2gmsYWU=","layer_level":1},{"id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"前端系统架构","description":"frontend-architecture","prompt":"创建GEO前端系统的架构文档。详细说明基于Next.js 14的应用架构设计,包括App Router的页面组织、服务器组件和客户端组件的混合使用模式。文档化认证系统的前端实现,包括NextAuth.js集成、会话管理和路由保护机制。解释UI组件库的设计理念、组件复用策略和样式系统配置。说明数据获取策略、状态管理和错误处理机制。包含响应式设计、可访问性支持和性能优化方案。提供前端开发的最佳实践和代码组织规范。","order":3,"progress_status":"completed","dependent_files":"frontend/app/(auth)/forgot-password/page.tsx,frontend/app/(auth)/reset-password/page.tsx,frontend/app/(auth)/verify-email/page.tsx,frontend/app/(dashboard)/dashboard/admin/page.tsx,frontend/app/(dashboard)/dashboard/settings/page.tsx,frontend/lib/api.ts,frontend/lib/auth.ts,frontend/app/layout.tsx,frontend/components/,frontend/next.config.mjs,frontend/tailwind.config.ts","gmt_create":"2026-04-22T18:56:47.082624+08:00","gmt_modified":"2026-04-24T11:01:58.108304+08:00","raw_data":"WikiEncrypted:caZUAHH9Plb/hKq4968GAlxdfXo1OZ/T5bAEX+yDDFnwmkOIiMXkaH0ZIHauIC0wfdpuxtoUKmX43kiFQyTbPAtTiYEiDR6Tc0QitLHu+/t2EuUEwUv7xUQwEV4sW//IvEpbtqaL5pRUagOGJPFa99C4e52Nk9vZW1Kx2qPB4qhq5J3Yu0nD02qlXghyoNL0NJHwuCxv7EahSsg/DYFr7sH0a3S5ETkZqxe96N44pBOsBHzuIrVBbRVxAXK34mDFp06Mg6X+bx/FzcoakGVIQ2IA1/sQmnUSpwDxGqn3UvGx6xVk7KBPYjKthY6SgyELy3XXUvLqYYrMzXJIpLCJenAAXTvXsseT+uR3pZTNb8c8t6DMq8wmc/nSYKx0/o0eWgxwGCW7U/hzreWW7EG1vT6Wvls/+9iCH022pB7CS06DX6cdGv+wSYp0wvWU6q7c+JXjhvI3Tz9BouXfgOipLBXfzo1GPVD211oTxUEOthWdIsJ/xrK33RKfN0edxP363h7CV1jAUHsZPO0hLP6ZZRpC7kDuFps/PTY5k+15rMjKsA3p4d2gO79r8IJ+nN0PDwK0ncShwqlQ74k0G1vS9tFBnH9lhq/1UdozkYQsNxDa5+YN28fNiYVXPNLS7cqj61w7y6GbW1rL7QuJy4pTuPCl1lJrFqDN0xi2a3KM4l00HZ9qbBQPyC2zF3cSmK/bbd8R4rrwbXzSJKOHyb/7Uhx0mbARihsrOJ9s68hspwmIvznUBYnF+y0y27DfTemQ5/UpNlT/WzU1zwIk8xA0KX1bdYS+fdH/CRZH7axSnG0WcjwloudpfvLbXWzUGypiGhAvZSnTEATuWW/rp86QszDvxQXgB7N1OSJFUuOUE6vxX1nwr/YGFsk75EmWWRT/5l3BoNW5rsNqeaOLPCUIe7RFj4U2hiWsrhjyXXyMpm/dpjmAIgPnYGeaPQ6+3ndGg1ooLn2zeijt4pY+yaM0JWp5giDt8jr7YhAcLRW7ojqK8IAhk51K/khU5x0HFI/rUYBS3k7j6V0pkUQYziBrVpYavetotm9w6yw1tQrB4G9Pkh4/NGGjdJ9ZtPdoAhxwq/vFKRixUOxtOzPW+gjiBJx5aBFLlGh4OeNikZu8dkvi4o72oyn86HfoxqjayhfyKFjnAhLuk7u4H7UAw5+imyWFIuT10HE4ku7WESF+jU2I9KtomZm4+j88sEG1m/c2PAvqMWR/TbzgZdogHbPk99qTZ9/Gxa8sAEqijUgFeXZHhD6fT+Owl9unUBxIhv0T7zY7KJFcowSL9eOirUOnlOuZcqFUdFT1pE9B9MpnS+aAo4H68NaI+k/JsFne7qyToLEjzezrMiWggu4qPvxqH/1YvhZKbm99SeiGQ/fSWhVKN3kcpby3wdWau5I3Eg0DApusN4Z+nnZY3kwY8CbBAHbv6lx5XVCfA2tw9MHDPpiVaxmBdA5fWmu4HSnt0v0Vrb5r3R/ZVl9ERMQUne52UjUl3II1fMML4ZrZzOexAOnQ1WJ+zHyQjGkcBkU6xS0R8uOhu5xA3obBmqzzET2RslAFXre9XhksI9E/qhzxB5abhiKMV8vs5G8GNJ1rQ0nQq0M/BbL6Rz6is7oJWTf8pL91hYykA0bUMRKq60t6umP9XKaKzF31+7PIs18PRJQ8Rzji9jXk2GJ9TpT4sc9ty9XTBQg6Je/vhkN2SlkNbxA0RoiWRMA5QxA4fnjOxWOFdP7X8ugdY1SIyFHmAR+TiEiGbH6qjNqMQD+PTmmi+1s="},{"id":"9eee7fab-6cd9-4ef3-9415-2f8137f1d199","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据模型设计","description":"data-models","prompt":"为GEO数据模型创建全面的设计文档。详细解释SQLAlchemy ORM模型定义,包括类结构设计、字段类型选择和关系映射。文档化用户模型(User),包括用户属性、权限字段和关联关系。说明查询模型(Query)的设计,包括查询参数、执行状态和时间戳字段。解释引用记录模型(CitationRecord),包括品牌信息、置信度评分和上下文数据。详细描述查询任务模型(QueryTask),包括调度状态、执行历史和错误信息。包含订阅模型(Subscription)的设计和用途。提供模型间关系图、索引策略和性能优化建议。说明数据验证规则和业务约束。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":3,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py","gmt_create":"2026-04-22T18:57:02.317816+08:00","gmt_modified":"2026-04-22T19:19:19.281909+08:00","raw_data":"WikiEncrypted:klcgW2PbPxJambbKMzvFtzxL0nPpsuPMPxr5hj83lS7k/WfePQWgQNKbEysjyVqFS8lXlJL069Py2sSf8yXxHJzOE+5qAqcKClz711a5h2iXkF0al3mIdEvPGsZtmu7Tz91D+nYN6P20/dGDD6jbfsmIRXLEv3fpccmaTd5XoNj9Y/QT7a0xg+LkG6A8bzQONV8mQsFJZMj512PXdrzG8bSiiAdWa7PEbotJVKJRklAdLNFr4FCsLXLsdS/G2RlAo97zi5J4mpx26Q7SGM1kx14TxsQYatCIUYP+iZ14NDPPPp8tQ+HGPLEonVbYiRiktzJo8Iaqbcsh59qHBoGZBndXEwalDBXzD3sIbYrhxlOU509HDe43hiq+M5eC2SEeTfGdYZ412t/aAJFPEfq3dRl0wa6Oiw4t4rox0s/f+rCg9Sr5yX/vsXrADGwowbhqt/EdTudfsdha7MXN3Kn9e9TckQ+HOqdgqW3+RnY3B08ijVPZchn/Y7XZvx8GujUHSuM3x7EDAXegqkPwkfR+hl4yb4BuuY5AC17g3hvn9yDvBN3m/Ky7mJ4Q9qvXfFaUqDE/FxwPWjugAnVOgAmWns1elVLUS/2nol2BUAuyt1w821y7+N79TkQ07amTWILYvO7I/5v6hStaHk5+ftwpaWSLofuk3Nwbuab8ULq6lj/Tz3uWkEg5/nIIYGVDSN2y9JKgkNta0J9Y4C25DpKnPb2HPfbnD/315IEyxKddS9DpOHC92uT3Ad5v/X0LgVsefqUUep4D2mVUeevDE2o9NuUqYyWYu16AL2UaQOWH86Q97+Accmt37g5580pjdVyzcgVL6Lat1P4W42Nk0vOIncIdM8Bt+iWUIOjmIWDK6nUytRrluJ6RAGeewol6Eb8eMy65WkJ8SsDWFj936G3imq6uoKEsmn9kHznKIfsvt/p4IAv+IbkliuuV7/VNQdN4jgfgKyRp8b4aQd35Qrv1ypuTdf2HQS3w/t3nb8hBriaZZc8a93LekZYaGpvrws/aq3ESXMU+csJKfWhEGhH4VT4cjy6j+jHgihUuUWhO1X/Kpm8iseqreG85CZeU9woTd/nPIayXO14kUEfNVL1ih3p7GtsFGDYpr4EcPU7JpPp61gLhfdpHydKVDLW4eaaCuTR4REP2Vs2BxiwN8GCpJcCbpPeF52n9qB1DE3uIVBITabqC0jiIHeVfb8caysKpddelqqLNn4GGL7BeUFq4RKhlVTmCGuBRWABBDEhDRHXsScje6Av8bOxE/QFVlZmFE8EkDM/WhG9hB5BQ+8u4pKPxsL3/n7xyMyrBnO2n+nTEGscgwlEnpxknYpBTrtZQgU5YB8KRGG+VnvSlbM95vPmdiXS5y7JM9ftKUbdxgnxOVrM2ydbK+5IGvaNB27szvHBbvqtxiY8lXfLRhMYcQEIcD0AM4Xl1qH90xIrHF3lHogdPgwXR/UWGRDWDXKVUEXGRLQHTlRTCJ2oRBGig4FvIztUbBVqouwtJBqoGXoMET7JbuNkxdHs7pfsL8sV5FksVAyNxvV7rRG5QAMaIvUMdDT+XAhtcrNagCHcb53sPxuz9ldlj9adP1H+FxOw7","layer_level":1},{"id":"d9e45b2a-6443-4a9b-8ed3-4c3c04773772","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"UI组件库","description":"ui-component-library","prompt":"创建UI组件库的详细文档。说明基于Radix UI的组件设计原则、可访问性和一致性保证。文档化基础UI组件的功能特性、属性配置和使用示例。解释组件的样式定制、主题支持和响应式行为。说明组件组合模式、状态管理和事件处理机制。包含组件的无障碍支持、键盘导航和屏幕阅读器兼容性。提供组件使用规范、最佳实践和自定义扩展指南。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":3,"progress_status":"completed","dependent_files":"frontend/components/ui/button.tsx,frontend/components/ui/input.tsx,frontend/components/ui/select.tsx,frontend/components/ui/dialog.tsx,frontend/components/ui/table.tsx,frontend/components/ui/card.tsx,frontend/components/ui/tabs.tsx,frontend/components/ui/dropdown-menu.tsx","gmt_create":"2026-04-22T18:57:04.216865+08:00","gmt_modified":"2026-04-23T15:22:23.573963+08:00","raw_data":"WikiEncrypted:mOhGqVhKXtp0S+QeVzok74WypWJ7klGHRH+KdUSnimLTYfyBjBDRPAzXT+gcOXfQVvcrNlnW0hq9eH7zZFCqkZsBgmYKEU+paWYmItwEmPFSm8j97/vwvs9ugP1aTV0WKgu1SgAg9UjbHTpC/aH+MMWl8IEcuuqWfI5XbGaUR87WXcEDmdrb3wUoUJRDu/cGjCf/fvmakwSGbuyVnUxAKC0b89qWigFSx7MqlY8I3hXqAtSNiskE28duoh2j488f5d1qN4KsTvxvRe26wRYqlD4qzi7WQGBZQUoeoyVRA8PrJFhxeH6clcVYO0kStx160hPPrlpF93ul/lDmdVwrTZfpWh5RRY5u02+lOo2Vcl73yz1ixYzt/OXYaenA0jUTFVdPJ2OcTZGDQV7xMOPFPX3iFNKxuHY9aks8ARFEUs2BtyH+KlyKfPdKqDAlklqIVzP4MH2E6uDcvYMSORu7S1T+53+R9br9Cfu1PSZkuVdmHNqUuKSLA7pMI1QiVYXtwk2GYmRGYUH7geeQddC61wxpCG1rXcVzBMSS8LxtR3SSj/9VQ0v2YyrqKzRh44BKjm+ojKbz8rNcf69UZ5Fu4dU5kGqXy/XWbFbSmoUmrWXnZ2zWPhMIgHAIsTe/iX6JC5Q3L70XVbXk4S/ffk/sKKtdV7XrQVmVPhSquUc7x1RcfMyLVgxyoFEOwwk9LfQIPE9n16lNCvDWX3UuK2TDcqDbwJQ/FMmjaZDilRQFs+8MA5I/UUtC5CyzoOiLRXvPqQQiqXjBs6jefxc0cpGAJwUkaISOvQum6WtKWK3y1CphRMH2hkB4bF7NgyOm8z/0JXMSpcPR8nMUY4M8pW9MZYQEL76sWcQAD/oiWlgAUccgiRPnCiU0Xz7/MplIj0jTRwXXzc8arUGle1DmiJFEVmztGZOQsIGDqSwKGG5XHEdLyKe2hWHqBGRWkqZrsBqS8KrFUWk5lefvdDZvi8ci+S4wdZQX8IDx0siYw5cfdMlilWuaptf6qf/qEVaIO5DX+MMGPmGBz7jnyaQfo2QWlpybbe/uLTvhZTe75uY9Revd+DPo+zgmDUmGj4hSliiZx0smUxDq2wMZmKLx3x7N8m1jdGgqT+LVQAhdUcmE1Qx3W7e51K9wB4PN3L8k8bDewzE25kuU6a7QpDLdn5lSa8n0E0Yug9cp3wgllhZVFVmyjVr/oC3c0I5z3elvtrYub9jPeRtR4AmW7w2RPcUt/8f7j8aMH/1lUBQk+GL6OhXAEnzmav2Q2smdsQqWS4cVj/FV1lrfoV+peL4fo5CxYMv/ZJSvbJaFSpBOPzf09qJBxUptVeosUyAUDv7YsJdUo02ZE8B3ZXZGcpKGKSRiBeLQKjuqkck1rBeJK4PnEEXZ5vtz2ONe8tddj5qna0a3","layer_level":1},{"id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"核心功能","description":"core-features","prompt":"为GEO项目创建核心功能概览文档。详细介绍GEO平台的主要功能模块,包括用户认证与权限管理、智能查询任务管理、品牌引用检测引擎、多AI平台数据集成、数据分析与可视化、报告导出等。解释每个功能模块的核心价值和使用场景,如查询任务的定时执行、引用检测的置信度评分、趋势图表的数据可视化等。说明功能模块之间的协作关系和数据流转。提供典型使用流程和操作示例,帮助用户快速理解如何使用各项功能。面向不同角色用户提供功能介绍,如管理员的系统管理、研究人员的查询分析等。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":3,"progress_status":"completed","dependent_files":"backend/app/api/queries.py,backend/app/api/citations.py,backend/app/workers/citation_engine.py,frontend/app/(dashboard)/dashboard/page.tsx","gmt_create":"2026-04-22T18:57:13.330097+08:00","gmt_modified":"2026-04-22T19:20:37.649775+08:00","raw_data":"WikiEncrypted:luoNp8LvFa7zGThvIT9T4gfD6KbzJyTAydbcRfVv0b4BXBAF9G/unmbHb0x4cm5f5JJeO16NqGe5C5EiggSB7moDpXZy5USSfpQ0OUKuil4F/RTioDPMtSUudIqxEjBd5ipsj1OYjuKwvCZDE5FVOSWKxyx9ABPAcj2ixa32ZPlrgZPKHD2EYG0qdFR1nrcOheMbdmmK/1DGPMM99yCcIRnhsKb5QMmqrZbFGo/SPCSXi/Ykr/zd7+VtVKLrPmeZHpaF0yafvwU0Sk0I8ne8YmfwUGC+cOZoDCI+UsE8IukB5R7bnolQRLXvVZdnHXG3b2DA0X4DxManWdKVUyJxI0KTcxcdI8DrpJB05TyoF/regQH6cLt9xm5r6oC5exXEvwhmfMoZVqZ2jp/7LVs83k3vKksFtqXA19YrxFliE+fS/7xxjhqFqC8gfV8eLWpHyIKgVobBj98SpzX6tRTXknjSX2kDpfKG1ECCqYBxGl+EcY3ofgMb9dgxDxdOaB1JU4iP8j0YMHe0vASK6GweE5UjId3SQsH4Qeng09dL1TY2uNr/6ZVhraG1xTMRFHeZNdCZtAWnUddTk6fiDJmF3zxyL7Wvgdc5vmSbfg0rFxTdxZEiGFHJoEQatTaUtv+NOJGQtnOuYzrhs6G59N5Bu3hnsT2Umn6jFryaWwluQaphllqim1VwA12J3iVLQZFZEVBhalhF5GQBDtl4zt6GFlKucztFwPZXIZTYJavPQP2xpvFDInehpuQcHilp3yHcA8+ucs0ani/GPME+nWnxyEDPhfu/FHkheybrXg084bLJG7E+o9XWBTlbISgl/1CuVNeWNj2ph9KIS+TAcq3NucrKast8dNM3bayIymMoemWvEcvuUjoRlABuJKAeAUQ2q5dFWVAZFvlK8de95GljY869ODymzBXnPjMOSCmHwZ51ImNKeIgHybmDkzT72uKyQcN8nty9DJKz0k6Kq5kib65fLCcoAEe/w3d/WVpmBqxU1Uh3yD+z1nEm++DCQTmK1jmwwLT9krps27ULzjOvLuJz2cJnCpSFeB2fBYxH5Wjbp3UZFwDWJWan/9xl9bIREOaZ7mmAz3b7YgA+106K4LV/Y4vBjtitwaM52IcTqvh0m2OKpQSYopXYE7hsG/CXE/MACxmx37ut0KpTFaM7N2GYOE8Z9hIsM53ueQhPuRvk2Hb3E8xbBs3mMtYON2ubkxuPdcQJmCKSHZTgVqD7NVWXIyDL87TjV3YTbdGq6KlIptH7MxMpAvL03xq0ApGXUlF7gt9qwpHG/tuVSmjPBAUAEXRZ3bC+1E0tvaaIPWgP63+hhl5S7970UrDCXrtzeN3l8mbplzeN8BTm9brd+gziF3NKUZgA2yM/OiHjy2jbsu2NmXU8Q3f57Q1MnJglrwSgciwgohkp5Q5XIBOCwyJuIcAxO6LJWzaXB+WOrB+xk7v3h8qxpMdfHMOLFTY8M5Rf6MoGtJPOtFpc1+0Cjg==","layer_level":1},{"id":"f210509a-2381-46fe-8c22-0ed768e6ca70","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库迁移","description":"database-migration","prompt":"创建GEO项目数据库迁移文档。详细说明Alembic迁移框架的配置和使用,包括迁移脚本的生成、版本管理和数据库升级策略。文档化初始迁移脚本的实现,包括表创建、索引建立和约束添加。解释迁移命令的使用方法,如upgrade、downgrade和autogenerate功能。说明迁移过程中的数据保护、回滚机制和版本控制。包含生产环境迁移的最佳实践和风险控制措施。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":3,"progress_status":"completed","dependent_files":"backend/alembic/,backend/alembic.ini,backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-22T18:57:14.161329+08:00","gmt_modified":"2026-04-22T19:20:15.066432+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkH9ryxDJ0NroguMukGrnBDccbI7FhPTNCbxlVVf68ZQ7vvUzAxXQ43tY1R33KAEW91uvBjnohUVl7Q+D/Ap3SUnHDpWQWBM8qdBbgPmANzeAhinu9R6LqaM1BaUXXk7OeSNamXR7nrg52Su/KTt/eSPCFzeoio7iY3vORVHeaHpWs3y+ipYf26jobCXk1cLVjF9BgaKQ8UIEk4JobP8DZM0dSC9SqfPLDnh2e6k9t39q8JNd3MaV90E75j7KuZKZZJemgTfwdUTe5c8Bn5uNxCf3TK5iuMxVxJXD1PTU+9tadOMcx1qXGJ3cb3nuH7g/03z2UrmsQfIRf/cZLGBqAdGIWhQpJph2OlUELy5WTq8t4R//c0t+IUVTKieR2A1E1U7uGurYXL5ymVtiLnckbHeLMEoxbJYmh7d4xn4mWF5hcIhAZoHvjqh+shIGNwCfXJQGswpnJNML0vWzQNhsJ1YcTUnHC0P8Y6nj9VmXMpUYuJLWuIRuqBS5lkS7ChcQMXO4wfad4N4RMHX9jLYytT/wOoty1KlEalUzriEMahdDn7h2DsLzOJL35SLwpVZ4NVnInvcE89IzYO4wyJIz4NdOfBYseoIv20Qv7qO8B7xhRtTudUyynfaz1jmkT8F9UgZFcdBJqg08MH6VdQSdrlKqUGSGsFAxtB9OC7yv25xznJq5n5SUwpLmFNbQ1evjOqqsogzLg8vClnH52aVuE6TfQWggj1wDjxG7jUj/W7mHSOsDI6AhtMWrP+2OVg2Wx9Bab3iLivdVe+mg93LH2FvF3a8iAdcDRseeNZj2UeJJfYnmzpsRpm+CeJo8Te1ab8UeOeGebDsnVTTILuEg+qe85nTuG8+PmgOs+n4r+781gUSlyoOO2Cde7QwES0X+oENbplkkSZM719jK09dcnbG27vqoeh8rTrzO9ygM48IjQzZWUJCnAIP4Y7VVrcTBiyrZhRLikSrVvSCvWU3K7KW18pnOJh1narIx0e6w+bctledpWsEGZJ9fwk/ae5P5ZvACxfM/2LOdDFqshVbr6grRIeSNNf+tl5nDunlOTUEY8fGNt4lsr35UgKwPwO9TxACZGCsd25DuEtHum9DU/GYli2+rgNaOokcc0Xtw/R8OuN2pa7ohiD6ACjJ82m0kKC0mBBymsNAdo3bDXv3yoyI=","layer_level":1},{"id":"aad61788-1dc9-4682-b743-47188d7aecb6","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用检测算法","description":"citation-detection-algorithm","prompt":"创建引用检测算法的详细文档。详细解释引用检测引擎的核心算法实现,包括BrandMatcher品牌匹配策略和CompetitorDetector竞争品牌识别机制。文档化置信度评分系统的计算方法,包括关键词匹配权重、上下文相关性评估和结果排序规则。说明引用上下文提取技术,包括文本片段截取、语义分析和相关性判断。解释算法优化策略,包括性能提升技术和准确性改进方法。提供算法调优指南和实际应用场景示例。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":3,"progress_status":"completed","dependent_files":"backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:57:14.593043+08:00","gmt_modified":"2026-04-22T19:21:33.125768+08:00","raw_data":"WikiEncrypted:qByx+WzXalKNnda2aYUs+KheFrHbXoPYZO+RPCaekyWxjKaQvamRZeOm1WgroVS/6iDS9zNWvth+zIYrS27hz/NZLNtt2wOUw9iZG139S+OGMVcZB6KjsnlgG3fSA05ZEdrwDfB531npeEpy2DodlOkcXOSBrgCwkOsVexBDKcWLpthBpfOCieqWsVnTfFkeXE8VvMLROtjojlr+6So18lnYzdEekhgU4Az61W3QEoXC7l+uPBNpRUYZY9z5nLzihT1o3I2bDEfAACTaa8pU8izFltiEd4qID4z3TepI7IuVr7oTmPOaD4MzHULu/4RaMo7/7c9Ql0uGsFrxRb3QFXiiH6QZN++2X9EDTl4UjA5k2E+OTcO2UOZm2dV7vi51lNAZwI50VwaIjtaC4LrPpX7fklk3hQ1qbw4w0FPjYlraJyO5MLseOOQXmURr5BCOhJcWoJmwJadtfh8EAO/9XRK9CRjr2wpAuL9kan2Vkympa3UCszQwVox0j4IkjJNYlG/7UEt2ixgTU4pQi+CAJy+8tZGJxY1gk1MCILniaClaQQImJhi6TfYfWSVywTFVltVcxPd7kMwK116KQmtoiqet/DRC4rzqeEbb6w8I7HZu+VwSR1TXSN8teXJTRMAFEgg9vh+vAOconlX3LzcgvFPohvC+teXJqTADp9XvqcC6Xh41G53xVAvDteT9pJCZHMZsfgh0bErBFzrvnwSObsmJEkvWnlDRN5tdVsRIk9LGcvaflUwWHmIof5SJj7wO9fSm2BN0gW+VA9nbQxyuHt8YqvNR5D0WUpbY1/UDw6IDhAxuTh/6yyVt0HqirNDXslgDardkMaphsQs4xh1fShhK/PcG4y+xX5VsoXIm/tjfGAEXYIeGOHtVuldTaCxG32uSnuT/aFQh7H6df2Hhb7c576oZ6QbZ4HyiG+Qa9iZr6deKWdGhtuuUzj3FBAXLtLont+yuXSCWi/AWM5MOMVyScyci2LKIjH5haWCCgS4nm9tLvifzUgmdeycw/Dhve3nrgdkgO+bIRuUQxXRIxZRUdxEr0DKIa2tEKVeorc5pIX9m1bErC53nDhnrLBj4/ZQjHp33XcgGQ+4jAfmWK/AN+P/SNbyF/K6O0qlKXPqQk/w5bOZWCtcIjrDLhyxZce/pYHOGotrSGaKOK56cJA==","layer_level":1},{"id":"ac0658da-7670-4e41-9e57-02d9d0d50680","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"报告导出接口","description":"reports-api","prompt":"创建报告导出系统的详细API文档。记录CSV格式数据导出的完整流程和参数配置。说明报告生成的触发机制、数据筛选条件和输出格式选项。文档化批量导出、定时导出和手动导出的不同模式。包含导出进度监控、错误处理和文件下载功能。提供报告模板定制、数据格式转换和性能优化的使用指南。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":3,"progress_status":"completed","dependent_files":"backend/app/api/reports.py","gmt_create":"2026-04-22T18:57:37.837258+08:00","gmt_modified":"2026-04-22T19:21:24.246329+08:00","raw_data":"WikiEncrypted:ncgUburcUGIQoFYRn+jCfmA+PbmqRFCE8+U3jYVfh2v8RywptgptFxq5lhwZlmleN1AF4e6ox3Zeepx7xqM72ox5n+mZFIvpPAV03iG0mffmuvwBURuWuzG3zvukYRbxLcpPqC6v5q4GXBz/rMTsxy+K9HHfwtlYbga6fioIcJrpFn0O0GBCxvse/EcV3UFGM+LHRaRVZqk3N16dHYVOsIgwcqfz+E1qQhOc9tSvlN8OuLBl1z0ukshjGXiX/lY4xzl1WSrFXAIsz6WAKGLPlkePgVZg61CHsK9/iXfq1HIs4Mv/RYwTtuMKkyWX9+6LO+AwRjoeHSIVgJsaSwMBS+MqugD6JwGdLsb5/QGcsDSVaN1zVhbjD1WnJ01uK+tBWcULWdYGAkgo7z9A/YQJsV8PUfXfdZnfuydZi59mopfaX1AYtCXeceMgKnzkAIwjWUl72+Pwtvdke5upjMFgEvoy5NrCoYwpZJBePLoPrgu0kURoy/vWGZ77WhOuGQs2/cn/pk4vCFes3r34gglCIF0tHwwh9piyAabHid5VZ3EIuOlhBHL4O9L6zlAgO0opbo23bXt7kIR8MIjEqb8b3SoUIGY7PElOLeOIwJiz1LzOnccT84S/avMIJR7fgzi/me7mJyD+8h7mZ3GY/AsbFhi2oh6bcqc7U1UcO40wTqx7myMlwrMOo9zRr+aAfR/lqH6YwFw89kkxflBfKQ8X7UwPI/vFeOnYkPFjj7XzgHUtclkOUbxztMSSnhxiBMGzbNf6/hnfqT9O5xO2ZF4ufJ0t2Ci/vTK7mqMRvj6sBAzXnGCig4zpnDKbOrVJnB53v6AnqjeFLvqUCGI5Aj9nn+g4LDMtPzzDhfm/HtoxVJjclFmC6FQSLvHlh2FILylIvVxzY7rDDuK3bTiuZFz9Hw==","layer_level":1},{"id":"7cb1d921-44ed-4e22-8bf9-baba7ff8b7c7","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"新功能开发","description":"feature-development","prompt":"创建GEO项目新功能开发指导文档。详细说明功能模块设计原则,包括模块划分、接口定义和依赖管理。文档化API开发流程,包括路由设计、请求响应处理和错误处理。说明前端页面开发规范,包括页面组织、组件设计和状态管理。提供数据库模型设计指导,包括表结构设计、关系映射和索引策略。包含测试驱动开发(TDD)的最佳实践和单元测试编写指南。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":3,"progress_status":"completed","dependent_files":"backend/app/api/__init__.py,backend/app/models/__init__.py,frontend/app/(dashboard)/layout.tsx,tests/conftest.py","gmt_create":"2026-04-22T18:57:39.375268+08:00","gmt_modified":"2026-04-22T19:21:46.916012+08:00","raw_data":"WikiEncrypted:5RlNBsIi2/3o8ATlHuzaYHdvL7yJfTe6YPwFoSkO/GgZuVYfBQkVBn+1kZzpIDRMGSVFSuoDX3pyax2f9XzBxnZshkSCM7o1L+HEG+sgCns6EUSGCL3KfZi4emTF8vVzG/3m0dhVOWuoQXf3TK1+2Aa07EE3HJ86aWB+sLQgQyR8gNqS+MsRztbE2Am9O9oDis36vAh+tGO64VIsi4ulSBpI8D3+dRXcAI8RsujwrZpp57UaW+DyGg8Jkp+WqqjfbgBGcdkno2KfRFyWKqKLB1g6yKJCePYymOK9DHhXbdBC9mKr7EWc8T394B1klPsqywIZs0i3xy/Pr5FAuzklEn/8jhNkYpmgcVvXaZ43AUVTklSOgSC0cwvfeHd91QuNSlfIbIs9Xh0pfhmz3XAts9WErkdoph3YSvrNDMuXK9CMNhlu9XMkMCQcV7ac8ax69JKW4uVaVHcjbU7PbzOeQ7vSALRtfK0zhIWlbQ3za72G9FvDogDqrLfOBzEXA/cyXMdpeZP/ICE7OsSCRM/i/yU/K2YUAWnRJczSn3cX/8lGIDywmB0jU+IL4l7eteQD1Ea3elS3ne3N6t0WqX/T4jybDWQQZqz0+gOrFuJUKTQ18p+2afWRjcYZnqg0EMvXxpXaT5fmpQAxMA89c70flWUr6l+ZNckhODBS1Uj27vp+ECTFfhbNt2CmqrDWIfdobRz1gXYkZI6LR+xgc598+CJDjc6zizQcychGbsbPqawU+CCQfSVqPCknZLlSyJrMF+FMoe4jm8fpOVyOOfqGN3N04W6++aIiU3eZIMB0F/1pjONP/d5egIYaJhs0Zo+ciWBBR+Me05kVd2tyIK0ldRH8iELZu4XmfrNdcGPMTZsENU4lZZiJxIXbeoKUQF7KbjsDcLTmuXfl4jcPFk48k+LwUEE2fyaAoG6SFrEaDZiZ/yR292cbQegdgcOrF+/QZDnMqVS6yFRaljF5C5+ce7VNxUOs5dzK46Z/0xD4kXHkT4QT5/727yUeQ8KmshnsLpu0XgxdbjIAKa0UpiByR2sen9DI8GblyzqpH/4jM/yMtc2COW+MLDnPw7xho10kjKNljBjsabSa5q/wLnYGofR/pA1CmnrwERR7Cytik91YmtyTb1D+rjh+uOjSVOB5NqjX7dqhFcV0CLE3KfUAkA==","layer_level":1},{"id":"c45e66b9-1ca0-41da-a796-6b98f394faa1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"运维最佳实践","description":"maintenance-operations","prompt":"创建GEO项目运维最佳实践指南。详细说明日常运维任务,包括定期备份策略、数据库维护和系统更新流程。文档化安全运维实践,包括漏洞扫描、安全补丁管理和访问审计。提供故障恢复流程,包括灾难恢复计划、数据恢复和系统回滚策略。说明容量规划和扩容策略,包括水平扩展和垂直扩展的决策因素。包含运维自动化脚本和CI/CD流水线配置。提供运维团队的职责分工和应急响应流程。包含成本优化建议和资源利用率监控方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":3,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:40.355828+08:00","gmt_modified":"2026-04-22T19:22:39.446821+08:00","raw_data":"WikiEncrypted:AymRokkaRBrPd1uk5umiX/dhQHTPPm6nf5mmDPb1IMODwfEt6djM0VBnDWaMwjVsVSuT1AHD1pfVap7WBute6Wsiarqj6ltamY09KvCs0YHxEqOor+0AYSzm2Aa31Dwx0HGTr+fgwTnE6RMJGGceRIs4cV8RBM7Bs4/C9pv4JQQe1wx9fBauJxXtVZgZmkTwsQz1zMKUv/my9/bZ9Q05aHGQVWSs0vQA7fX+eO9Ugt8ztv2KzLkMHjTPQwDUKBMhAsMb47fa/gUJRb4vX0XaRC/0NRwbOvV9kGE8ZhfJSMzck20DTmUNjRs+txGlORGu4UWZsefqLmppB1YdHehQUnSp53vMgJwj0a9BHe2ZU8oB3BBo+Ky3c3OR4uaa4rfHtatz+jzKcC5vq+Oa2OkwFMyKF/rHCf5c9kOD3c9bg/wQwxJpIov1DkWxrbmp2EHHUtHsb07ASQhGLV3SX7POirp4b3urFGRk2MwXKxT5U/gA8wytKMJhKBFtElvFBq2i7nSPeaH2xj0DS3o9rwbrhRJQvLfp/3z63umdp/84RCiI8SwdYgPx4ACqLY3QKXNo0LIi6rsgWkaf5Suyks+dimQcPtAllHZGQA/gcWYidV5oQCnhHJ/meCiKRy7Xb4GttMbIeOA7UNNRQ9IFS7wyprb/n36lYgLOcuQ5Nugly0pl7iFTkl4qWn4pZ+zE4TR9CK3+3oihqJMUeVFdsWHHzgVsh4Vy/4MCPUipHMfRj4T7BabCmkvaTRaf6oRiYEXPGH1mUXCLnQuty4lKx7e8LxdqWP6gciPJOcuRMBYoeBHqUKw/JNmAzN8FuypXsdUryS7GDozcilxOcRE9j3D0JEW+8ONdKF5sp2JAXYX0mhqtfB+RscbqU7E352fF8vZAqHdS0XHCguOUcPuOk1PjzrKK0PJcxoWJPrW1H76CpfhWX9kC1CX6ji8+oMevPaHlwwFIAPnELyRyWOvaAia+6TeiAn8YTup3BXf//p7UweBdBGz//qMDvWoMqMf67cKrFP45gozQjSEYzm8AQ8g0Rqx6ctmJotfnBMpbUoG/k/Br9U3yCwUW5C4ELNIkZ8HMTq1vu6GKzheTjgM5lsZSBhR9qgPwf7cYyU47KLN2oWaoSG9Ke9U5fc+blB461oN7Tb9p1M9jYYAi3IfY13WbWR9kQ09yQOl6zNP4E/TOZ/WG1O8YhDVo6O9b5nQ7Txck2F7a8+Oqzy404YpIRpdXWJvx2sNjxCQXQVXqKKTnxP5lOsLb4vYZqXeHpIw8VawHDzn9M5zowBo/3M96UZSy84F3QEP3JU1nF98Rqg82vqB50gv8dY6wl5RPTzKd+Fi2","layer_level":1},{"id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库设计","description":"database-design","prompt":"创建GEO项目的数据库设计文档。详细描述基于PostgreSQL的关系型数据库架构,包括表结构设计、实体关系映射和索引策略。文档化SQLAlchemy ORM模型的实现,包括模型定义、关系配置和查询优化。说明数据库迁移管理、版本控制和部署策略。解释数据完整性约束、事务处理和并发控制机制。包含性能优化方案、查询分析和缓存策略。提供数据备份、恢复和维护的最佳实践。","order":4,"progress_status":"completed","dependent_files":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py,backend/app/models/user.py,backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py,backend/app/models/citation_record.py,backend/app/models/,backend/alembic/,backend/alembic.ini,backend/app/database.py","gmt_create":"2026-04-22T18:56:47.082886+08:00","gmt_modified":"2026-04-24T10:59:38.979085+08:00","raw_data":"WikiEncrypted:Zb5TNaG1u/mRrgPr+sDyCqW7t7yX8M+Ha+5tSgGfMUOChQVv8Rc8RrXA+lpSqmcv/gkaDzP81agTYjHvX46erg7PWFncGZ1TOXKqQP7QcGfliH5ak9tnEamgIuPyt7GD7X/ktYWZNBw0rkib1u8riLrYblHZPip1fA5nWgiNve9JAWR8A5LSXb1/MkK85pGhIT0hbxgGSC6PkPVIRisy/D8xDYn6rcwMs8isn1Q0j0kMKiUwDu5D73M4vDsI4y/ZxAWd6WYEFgkqYOoeV5KveiHRDQ1BWHqQDFCNR/UWM2lxXlj/whmN8VaSk9Ye/JHiiNYbkSuvcUcO2YiOPia8H44APQcfRpcKUh9SBToYsFV8Fu3Sz330VdqGSjrk4hlw+DAQy0ANf9SxneL1SSgh7UEQb3mCmwf4ol0W2OOEKOPj3+srwFiYVbOmSKLMUezu4sRx8BecH0DQJj+w6u0jFTCVwHJcsSZXsJ6ftM8zeW4Gb62L/9E3eGd5gznXE4MrfDGV0U+SHOXTHVLHjIiiDCFL5EKuriwMozfYOYiXp1kgte0NR3DLzOoxAk9NQViv6c9ckVvlxSytmvKn7bbuCU9m9ZkZwa/+maXmuIEHvYRmeD0JBzVAPZtqvr9Q0yjLJDSWQ4z/0GDbEER7obUFIM+E+N8/yfexWunfYvUfL0mWXCcTd9J82nMzWM+Wgy2xUD086AHFPLXHH07CREuqOjUxZsvdQDG1grk7lObH8izbD8w2Zxaayy9lIwqJBEPCqaRdF14OuD+avHkK3Llo+7V1HYjHFYLa73gJvxSO79Ww/qvzvLWynNytnZEci9NCrzeZdZ+0TKrk+9i9L/5cU33O7IFTcVDDUQKU/ZCbP4D+ICH+K0AmOTiZaS343BGpR6hGlcrljtEjmFjbtENwJ6Dj67zXXVvUFWRlWwnk1ueUMxE7uNPzkF8R6XnOJQZxjv1ZhoYTrCdpi1eofq2LSlp9DGEyVNgS2UvYp3ZKdt2nOQi+NGHfy4nEMXUm2HiIciMAWERbdIZFH7igmgNwCQvvOKfnwxsB9aToLxzFTklkYilSbsBc+lBi3dbwXpvyfvcETruYMAK6xpcl1vfnkx0UVzmWg5ScYPlMwAyAkThsdYB31r9HWM0W2zlrsan196zyJUp/Ga7/dTuGbTW9g8RIVFlbvyO2+q1QBoBXM4lBDOEZPZPxpCubiCkbvshTREXUBElpgabfbBe5oufQCqpMvpO22rjfEwEMp4XMcih8I7Me+WEJuO55dx7hs54WCDmTwEa9xLmb0hXAKG1v6asdjp08CZo4Jbvnp/BrARqvkJ04j9cZpY5ybL5tKEtCbWWnIkSTC14or1XZksHDT3UZgFTpCOoAIbC8wOL00HXgI+rkt7UFfccjoV/i+y2xOlkwPUt3/LqSnsYRftUSpnJIj/vsMl8Gt25CJqSzSyvVGY59wIhWaWWzMldJK0IvOnc8JOGNTLwumjK5BG1apFMsHQ5IsoaZlJ8jed5aM7jLsu4v7wCNEpb1mh2FX9ntfdmHo4fqvttaKBlZqzO6/2JSNVRJz7KekqHYM0Z5QJ4="},{"id":"05214c1a-d804-4f3c-9048-20ba4de3be0f","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用检测引擎","description":"citation-engine","prompt":"为GEO引用检测引擎创建详细的技术文档。深入解释引用检测算法的实现原理,包括文本预处理、品牌识别和上下文分析。详细说明BrandMatcher类的设计和实现,包括品牌匹配策略、正则表达式规则和模糊匹配算法。文档化CompetitorDetector的竞争品牌识别机制,包括竞争关系定义、相似度计算和过滤规则。解释置信度评分系统,包括评分算法、阈值设置和结果排序。说明异步处理机制和并发控制策略。包含错误处理、日志记录和性能监控。提供算法优化建议和自定义扩展指南。详细描述与AI平台的集成接口和数据流转过程。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":4,"progress_status":"completed","dependent_files":"backend/app/workers/citation_engine.py,backend/app/services/citation.py","gmt_create":"2026-04-22T18:57:02.318113+08:00","gmt_modified":"2026-04-23T20:33:37.372717+08:00","raw_data":"WikiEncrypted:5AsZyvafBXiUtsQ5ntd2xSs3ILjH2jK3KRqQeqYdLK3xV++pdLq+4satUA35s4AktJpvtIlBIE91BpoSSxdMIJzlzjcEII8kW/R0EytB/VdNUbQKg1RverfqOp1bPEWLBmM0oXoe7+3qkzPC2Mf1ooT1qY+Wnye4CAfG78TD/q0AMQdykzQydTep7eypfUng3BGXStCcjUkwnitXy9jgftpC0/tEyMhSJIRwfEyHMC8pCZ3uBu05K/kbWJMAVzeN+RbpjqQl/AMRIDLTMg6TBQrvrH5uB7kEmNLnso0k4IwbKjYBfsoAT1f/RhrPR6uEpuyMZCI7868kZ98SRi4JNdev+YK7Ek74Y4AW+/z0d/9fpp2VQ3lDuYYADB2ihvzHrK09yCDPV5DfYbOE+YmgfP/W+1ZayVWcVf5jjw/kQ0+wXXpByj9Bf0MvKeJO8OmWNbW11YKf1Zhr9O9ssfAGhQ61tEWdGwr2vpPRZecLhmP/3vAso3UexUhMF+42ursRQIxusBVhGnBG3395aphiScvidcQ3AWZDt7qWaigup/9WWvvwKEk+gWaJBnO8dib6i/mBuB+XC33fXmvrkk6ESP9afV1Ag2XJnNosrx5wpwCnwwVeYm1+mo2FyjpkCyIesooi9FNVuMYQUiR7o2ORBBXyp8r8l4pab4wvhmQ5F/kvyrDq2IUoSgVwCe1WVokpscxHDzemlRiqQALcb9vHFogShoOIw4NQd8JE6Ciw2NTcEbgq5i0hiaO1w/VhbUyxoqA105/8aSzbEwdAcuMG9ciHKwbMkoyR0UaMKUZLJy6VO02JFFpRtlh3OD72t3VNoDS4lWyWJe4G6NccX+XAohN1rsZU+ROCL8Y63mODms+oacpzuNvCQC0f91XvoRbftpDjven11QkJUdRxC+QBid+X3RB5HjEUZI6amQjQESEX2z28T4td0i5MNlp7IQfJjM00IuaVZmFavGuu+RJfvR7n78hqrcdjNGJE2t3TTozXstxH3HLmjwKzaA1DGdcvjISEAlWpSDq1Z+8ExFSDbevtUFgnb30/rRPe8E/+VsDMR1FqWh+HovxPuOeMpbUi9ijTGv8ynn1DWdoSvT0kIfsNMhReSibvIGRprPdW7oZEiI5y1SQYXU4kMBOpPdNuCyaPRA/3Mx5z0o+l66QqRA2tAMfS5JvFR53tL+M8eEjH5xvgW0VmBTv2+9VGk9aRLHXSHANLk78McmWR3P66okFWF0OhqkaLPqj1lqn8SMDBv297qL/7vaz/5ZMq+1nKCtq/I4rY9/FziNmhBZi9jtXj+845Jyt4Qi7hprnHQYqmX7caLgy44MGdtGDcZ/fxMNY3A2QbuIeQRT767L2gpffBKmqQxLcfEBwxKol5OB8/jdyvVTpGLMdROGD3baQASEk3njuah/PfjZcfuARA6oVvcpj+RhM9HEGKondRlyBHvD2f5p7nK7WyubfWPvcD/iKl45JOn7zLMHQYvIYu5w==","layer_level":1},{"id":"bfca5ffe-8905-4ac2-a0a3-8e4dc43533b1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据可视化","description":"data-visualization","prompt":"创建数据可视化的详细实现文档。说明基于Recharts的图表组件设计和数据绑定机制。文档化趋势图表和平台对比图表的实现原理、数据格式和配置选项。解释图表的交互功能、动画效果和响应式适配。说明数据预处理、格式转换和实时更新机制。包含图表的主题定制、样式配置和可访问性支持。提供图表组件的使用示例、性能优化和调试方法。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":4,"progress_status":"completed","dependent_files":"frontend/components/charts/trend-chart.tsx,frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-22T18:57:04.217105+08:00","gmt_modified":"2026-04-22T19:23:03.405364+08:00","raw_data":"WikiEncrypted:LlssVZ/E1BSUywfa50FLlWyGoIcJJpOig8KP9B9gWWZZI8ePi8CsG3BxaOR4OzxCxm2XiNUDCA5f2LMwvnigr2SlxVBiSNHUI0lCgSHHEunmkPytqBjFiqGB9yeyKz3O1rSdq/m6COB07RDEp6Tymfd/Ich7hNqr0ALiJKFBMfTRXbiXa3naRlzgzc5/DA1h/zbAk9yl3yaR4bB4p7xAmyNn8C67e2gxrbHOKN7NK15dfXoIag0XHJMVwFE6SysJ+lA7fykhvt72SHx+Qz58/QamURb9OcCEnEtIYqW1uga1vc2HXP+r8Ud+tutKATUxPch908D2Dm70HjZTkDqV0y1RwdTE86O++EPgx5Sx24CmB2Y9KEs2TsxQBSxas2iX7ajhgIL9xFqjJIMVJWfRNeL/ql2x/OsrzEXUWybjh//bQHE/MIs2lMcn3jl6uggDT3q//Zf/jugKwK1117XAp1NDps6xhJqmTf0/J+uk2DjJwURNZ+f/hL4XNyCoPSOpjPZMIk+ikrqwiBBFy1t5dz/fksmYdzw5H1wSGwFPks461EvwT7SUd3qHg+HDEWwCrMRQLhaalcb+5T4rD4Gg7Aa0Y5Q7v043Oz/0rnmFckpB7QJrcI4yUtnbNxu/HuY+NFZLqpJUrNC6MhZKZ1Nf8HjXwbb7FvRLPTJk/0J2UGgZIuFkHqA398GnAHSj3OegnBaKM+qHr8cVs0wfQ/uFwwYzgoBd9gSGURpkSSDhsDUj2XJMeQPghyYg+au4UrCpUVHdYOyliR8OyttchGTRgDox14AD6X6BPxBueyw2Yb6orKjSBwNfDa9SZQK8dW9S0BehKqK7QLDHIzpglx66chB/QwWwaryM7BrEciDg6cdFeFQSmV+EgDmEePwse6hlzNdSXObTbNXLDwYhtifAxjK0xxhVUCtc7HVAFKLROk36HCFnlzxLpVmtppYzoprXfyXDe6BHU55d+PSdjtYyR7k/tigqJv5jX3TTrH6McF+/v+eR2ZtsTDIjWz+prq1cMVTVPgIB9WoT0+dXP1fMoZ52xLzWjSkgrQ7djAo7jyy1G9plvOx0bdGh5lBGOz+/zY7MTLVaKx8eK6kKS+juFkRK2kCuesUi79TGLidetA+vkruZiHzNPBJWntDodb79","layer_level":1},{"id":"b32b024e-2d06-45c8-94c2-a07fd25ab9b3","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"快速开始","description":"quick-start","prompt":"为GEO项目创建快速开始指南。提供完整的环境搭建步骤,包括Python 3.9+、Node.js、Docker等前置条件的安装和配置。详细说明项目克隆、依赖安装、数据库初始化、环境变量配置等关键步骤。提供docker-compose一键启动的完整流程,包括容器编排、服务启动顺序、端口映射等。说明首次运行后的基本操作,如用户注册、创建查询任务、查看结果等。提供常见问题的解决方案和故障排除提示。确保新用户能够在最短时间内成功运行项目并体验核心功能。包含具体的命令行示例和预期输出结果。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":4,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json,.env.example","gmt_create":"2026-04-22T18:57:13.330281+08:00","gmt_modified":"2026-04-22T19:23:49.7972+08:00","raw_data":"WikiEncrypted:1aHEw3M2aeluf1++NE1n1HTCzLNrSYNKzc2IVp06RQtbuAYcMEXChpU7tJYS1f3O0opR6Xc/vB+l5keQe8PgCR2ncFv/1Td0hCZ2YAOzrKcU9vT19aDXTs2wVsNg8N0rDLvVcTazfsrfReCkGbF3t4KIDlALR7E9k/sBc8Aux87FRnIqhElZnBvZS4Wsv6VYjg+rG70cB28ZbZapx09FwTbE2gyXj7Ck6qNOm9h31VGeQcyIEPfTlQzKWWghd2UuAwraAXbHFeTBwAzBOPZrVi2iMW5N0fiPvrofJe2RpvtWwEWsHguXuXUfXywdpjyOFbnrTokbwQiiwiHpgbktPSypaW3QvBywnGVAjxPBIfRlzbrxj8jlb7w8YznQPbWcNRuYRt3TVMBHR1Ix8UjdR2JwWu4yZQUrLOP4XJ1OVoFdLu5sT3ug3YetVAWSBGUiyUEIQ1U7QoHxxE03qI1ZmrGvC069cAhyU3YQYL0g+PfXWWo86/F20gUXppepBbqg0yRPlCX5asdDuL0vX+i9vl/JI2++deWQKu7cSc8+5tRNcN2AF8Klslhvy5KUEZpxqPaEhxXek/RE8thYcMjT02y2lWMR/WID/CEUm0DZjOC2fQE7kYjogUTC8OhNTBXocpLyn1sbyngxfQ3KsE6+Ysl41LroJ5F7SN8+p5pueRZgBbM32odMU1Dil6T14I/HwltMjiGAjHurPSB8hcX7nNvkuZnVTE2YMjB8ZEhhf76D9Pp1naI3P2d3j0DprvLXRiuPSfO9NBTu6LwZKuMaI2MBEDI2zoV182wdrC1T6AxOiHNcJXYiaF+ZOpMA0vabvcycoioAE6VOZ0mBQ9ZPVSZDf/Dw+VTsC8U1qruh1IAQVYCHsnjY9etX9sTaj6Izd3VrvgQkqP5vAteSDZTy1FOTlTi3X6RzcurXdR3833HqpXa/a0ot8JiRdmjIG0ydOuPYeZPs+Jb0FMN85H71mBziu41udCrikCTPBRTVz6VCG9yBdOgeW4s/iNhPqWCnDibKpfJy1GfSyZ7Jja1d4K91Y+IHVrJxB0+TZPezxY/htgMg4W7MtRoOOPc0eRqst/S2zmEgxMMpU4dfaQIne5zGbUEPNb24qp3HsO9v2un6P17rFQV86RwmPCnyngxtddo0vUNesY0s594GhsGEquA9XlaYa4/KNM14pVDEm4ReIC1JvvqdiQdUAPv3nMXASqe3FxbJmsi93mpWhKWx2q4W+P3ZivXtxhQ5OB4Rs2uXmArlB3MNPKk8TL7wHCUAsFUcCGoPtT2+ov9ntDTLyjKsb0YUGjYUqAceHGdvLCM=","layer_level":1},{"id":"15d6170d-716c-4d2a-833d-81211a59027c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"平台适配器扩展指南","description":"platform-adapter-extension","prompt":"创建平台适配器扩展指南的详细文档。提供新AI平台接入的完整流程和步骤说明,包括继承BasePlatformAdapter基类、实现必需方法和配置平台参数。详细说明不同类型平台的适配策略,包括基于浏览器的平台和基于API的平台的不同实现方式。提供代码模板和最佳实践示例,包括错误处理、资源管理和性能优化。解释平台适配器的测试方法和验证标准。包含常见问题排查和解决方案指南。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":4,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:14.593273+08:00","gmt_modified":"2026-04-22T19:25:18.719953+08:00","raw_data":"WikiEncrypted:Djug3Ni1DAZ8Du2qShzHYuqLmnJOyyKhsCPSfayzAMoLf9J+rFBy0LePWIX3b5/HwiLgJX57X2JBlObsW70y9DLEgX5HDr3AAeBC0dRNACFssPk0GwpdFdJeFwRtoB01ZTdr+IpYAK2YG8gaEA/2ysFJOZzxpGWgTq/Xz+KO29a2kcDgYhZKt55uqT/Mo/5Dzr6AN+qXdLL5xSqrvCkpmhYMFmzgIBOUjJM1mUISEtf/X+gK0L0wXSj/tCJnDQtGJqbFK24HEYyVnkon1GdnIvb+Vptmby7Qg9iNT/xb8JEVTTLM92335BfpTwTp+D4fNkMNyZgXv/XW6K5J/dLRulOCKwxJxPROAyvyEc5xLI8vh6BGP2+b8TgKAKILZTXg3SemKVhGrB3MqY5+V6whOOMT57LHnuwJUEMNMJsswFiLp6UbAlqwiICRF/Jnb+bvCliw4xXvKC6xfAJDQ5qAtcTCAm0uGslNVB5T07pzLFy5EaJS00hqRmvac/P3e8UyL84KjzdngtT3yZ95yCL30Ad9SpGXt76JgCgVJoPFcnPYlJZiXneeB39wFX7rogSSye9XkcBSqEt2ZITemhNHF6LmqSUdnA3rX85S/zDmRiN2NjS1Zjvgc63JjB4B8gQhw3rDllzHDLPBIO3PNInvmVsx5zHOjAMZmyIaoVRtB9BQQnUdHn1WvHdRXmZfs3eVA7jNhDQmTtBzdGtJ31XIHAVkP5ul/NXNBKUytIXDS5hE2s/ZR6j60eIWBlCNxNIlj+42vefIOU+e5kJufMVcBv4aXyQHpunohRHMUYteEC24NO2CW1FNZJlH9BEyf8RKg1/0hDEmySMxcj/S/pXTp5i8nevE+JleHdj3zeyWlGqJsJa7arZV/Kj7qPJYtN4VHoDGp7MFHgKvq6W26lje9EuwJEikt3hqjinocemgMjzEx+PMVPovHIBXyCfuSOtygo59bhUm0pvPgdMmml9UgZeVV1GMzDT//kfmf33ZL+aXTl+zEmnw5fZYwccKfmY6Q++ZjfSQLB9eV6u79F0yq3zh7zGb4RqRR5ZeL2vQaNsL3wyqgNppyJMYSC6gX+ce1aAimwDx4Lr/EnY474W0FXvid1Xc6Bg6KdPrwnKJJpi18zMOmECI68RvMpwmM+92oe/m3dj6YGItooug3uasMy8SPsvLi1RV2F0CQD5CqYs=","layer_level":1},{"id":"7e66719b-4a8a-484d-889d-10fdc76788bb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"AI平台集成","description":"ai-platform-integration","prompt":"创建AI平台集成的详细文档。解释适配器架构设计,包括BasePlatformAdapter抽象基类的实现和扩展机制。详细说明Kimi平台的浏览器自动化集成,包括Playwright配置、页面交互逻辑和错误重试机制。文档化文心平台的API集成实现,包括请求封装、响应解析和配置管理。说明引用检测引擎的工作原理,包括品牌匹配策略、竞争品牌识别和置信度评分机制。提供新AI平台接入的扩展指南和最佳实践。","order":5,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/tongyi.py,backend/app/workers/platforms/doubao.py,backend/app/workers/platforms/qingyan.py,backend/app/workers/platforms/tiangong.py,backend/app/workers/platforms/xinghuo.py,backend/app/workers/platforms/search_engine.py,backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:56:47.083138+08:00","gmt_modified":"2026-04-23T20:31:36.620063+08:00","raw_data":"WikiEncrypted:wpnkiTiqqfzSOLf9jfRAk0Q6rmj54V4PX4cfdCN1v7vUnV27EqfgO0UCzli2MtUnJ51CgpvG/pn/E3FsASRJX83W5OtoHXDNZ4j26fcGYWMK9zRC5hi8J/dMZoaQzJzzsT8qKvXJnD4D7Bjp4ZqFEme7Smze8hNvF5wytAi0n14HrcR90C0v1NYf6UWM/I1F5Nqo0+3N+pfMTr9vJAv1ZqDstNHpvNePzJyNYVmfwpIE7rezCdxATA1CVuPpwaFA5xsmJ+vkqC26R1ecrjj4kaKngH6RRRDgQhhQ6aRB3vt5nqJTkK/GUHcF5T1XjKaL+a/sKF+40wgULRooeO7uAuC8Zv55v4uHR206FqyBmzQ2n2oL7aEvTlkvDbpN4K4o46nOw6eAh4cC2u+M/6UyRJ/vHl8dGbnZjB21BICs+8mtyY9X8HX95c3q/eXaBcsnPvE/pQo/8Z6wSj7GzmxfueajIQAC0N3PypyM475sPJJAQYRRBk4tB8BeeHAheffcSAiLI86gW5xCar2+kHIHTkRg3pcdkaw1EkhKeqcQw6ew0Z83+q31K2+D+G5Dp7k0yg57Yy+wQYoQpi482aVJTCvTl4DM1GdhaLBYK1/O9ybs6CsHHuhAMGPJeOCtMI8ehbz37vhncd/r5KFUwVm+e8+iVqLPjIA7A6uUm8oef8IZswkzAIcBjZTd0HQmfhdO7p2GfuJKvyAMwWchCj+pryelFxsQ1XiY4QCO1g7ORVxu6x+4/k2PNCOhk6gEBxOjJQzXNM+PjMhiZHJslw5eSbtEAXm+1F5jyhyYY972p9cQQS3iRFts9dQK7qtI8+zm8/UMh2S3rh9y089hgBEUB71Gg5cUb7gaiI0gJYh5HrUXvqt3g6H5zQQs+913IJZ7giMElPAP2Qjbk7hKfAuLl+gm7pG21vEiGBgdafi0W/SeGMfEfargk5rycBiAux4yqzolMzt6ZY1G6bSEdxhBwAL7IPHlaguENQ7PIDWDT1mlEboyeR60e3xngdX3d6vQeuuV5+OWjDecOeZTiBxvDIPgHbMXc4UEzS0YKWD8ao1VsXgT+V+KP4QhvazHdx0dXUhAJlmfrXF13WzadCYVAAlfJ5iNGkT47I5Z7NwqDIF2jO1g5hfgR/LgTwdLyuzF0R79gBMRfYZusLAkvoVjfKdTxjMIrkuXKoXEbgtcZDj99mrJe5eVpoCtl/nL+FDv5U8e1VDikgYWnXY62y5ZnhnOcvlUDLD2mJVlDEbnDBkMkFc2WW6TRTZQAb1pLCRTbsDr+kQD5BLd0YLql1xTFN8IsAKgz3fkhafmSS0hAEBsKC2Ntov35ZpS0cXcMYb1oGIIGPVAMq4Uk43QUUSLac4pkX/xpRkDI/wPdmaebMbCDw83xHKBNY4h9STf5rFicv01m7HLBHfkB3BTFwYsKGhOqxnJPkYnD0ZSz+ia3lw0eV2RoqWx6ITdxEvkaka3zPxNSnqrnTBwjBwTbLz5tXrCmK8Fn5Dd5N9xlYM6+6iveOBt9he/WYkedO6pClHq3NK1RmLgTQWpL532vkJNeI9p8YUcv89XqnwXSi1YhPMe1PKgYTDGoZvsPk66RDWaeTNkfhF/vcZudTvgMmZzQVRfZ/clH6wRHfgZzl1X4HZ6WJ7PKSSwwUBw/jkvMZ2rixaio10OXuEfyOqYqV4EoQ/upbXArnmYKjEbhcULNFk="},{"id":"850fc702-3eb6-45b4-acd2-ae87fec1f4f1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"工作器系统","description":"worker-system","prompt":"为GEO工作器系统创建全面的架构文档。详细解释APScheduler任务调度器的配置和使用,包括调度策略、并发控制和错误恢复机制。文档化工作器抽象基类(BaseWorker)的设计,包括通用接口定义、生命周期管理和状态跟踪。说明平台适配器架构,包括BasePlatformAdapter抽象基类、接口规范和扩展机制。详细描述Kimi平台适配器的实现,包括Playwright浏览器自动化、页面交互逻辑和错误重试策略。解释文心平台适配器的设计,包括API调用封装、响应解析和配置管理。包含工作器注册、启动和停止流程。提供性能监控、资源管理和故障诊断指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":5,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:02.318442+08:00","gmt_modified":"2026-04-22T19:24:30.529121+08:00","raw_data":"WikiEncrypted:NKkj/YX2GdbxYjFllBaf8+HUgx0ecKFsz1U3HC2t2IRMbOkBCmoy+IYbhzuQ50K4pCdPARIwK+MaHbv1MDUXpcbdnvRL12GKezTnD100oXzQKqQkhZdDDC4nIEcp6weWLVGVffqyB7aL/dnt1QlE63XyJfCwizBlecxl1GDUB4J0O7SsTFL5gI6enVYO6hOzx3JrWnEFzirRjA6Llz1iFiFUWxTjxjToT1qkxAdREq2omi39vXL1s84I0XOA1blljfNNIGbpkxXW5uohJBndl6l7Bh23wF8z1LfdAavsFmljavCWqoMvA61Dn4jpJT9oDmaKXZpVSuxfMF2Tu3WOJZwISUGfGBJfdbfxNalhuFff+bhZR8P717nLoM3Do7T26rsqW/pr0NJL6aKxrlPCeIzL0v6Ct+HU3ULHT0EZpG8HfU2NhGWAJd0NhX8RZ8B2ZpfXZKioKtCkLhl4oWV6P8/k5g1nWpnP3wpmDwvp+/pGBeaBcYSenwJWgcGR2s0KgVsEW1niM8+JLaK15wFrmKcxve0hIWBiiPnbZKscAYq+5hj3ecte8h/JevEf+SBNB7ify6uUGU3Eve1jXyPeBrc2FCU5ueeJSFD3wu5pHlkzm7PP8UAbQOfwmENf/Mc1YRNi1FJsujdQuJ67474CyCTkCWFhTC539/6iIa7hN8505GK99PxHcIrsPMMT5LU69r67SizSnWV5bawiMPKGosexCHZfhT1jrScQCKeuld0X/lE1WXXm6ADBbfxZrn/iEFK0zc0WKsnT0X/nQI+ycJaw40Cm+soCO6/KtdYYGEzpzViqi2KxYhRyey+o+yIi8V7nVsxUCbaVRVmYNjnK9yX+3ypdVpJLIJXQ5ywaUWfvqgCrsC7Xxba9P9D+0kmnq6jH6ZdIuubXp0yOtWxe+VC4bHAWoc08RoBdLrlTCGz/hmgi5S83hM8MN0gLdQtc2YDsc0Pxw60+ylnkdlKIefBmb7XPiD8RMRvcbDUCGnrpenbxf5eoWLjLWfyULNQHoYINDdIFvn+skLu10KkfTf8lpRNqd2uHkHVhTTCFh25GlRLAdL7QDHMMQbmwG9OTjjt1tMlW6aYJ/pvYQq95uzmLAiICIsf+nT4xgqoFK+tTBmOst7Z3+bj1YJCPtUNyIzC9a3YYfRwlB1ckjgJaCURcXpImdkDtdpl3GP2mtDp9O52ZDAQVAJFVA3wFFV1G+qjqGRl4cDFK7BlAs04O4fvskn26jrDYiVqgdF0pc6eIiPhAJg/1BabciIggV78rEnEg6jiNJ8AhUmKLo8JOvL/C3m1mfcaUbU2K7oK8damVm8BSmIypHMJfCXzHIt6i+CaJLNlZ+c+MJ4WhqgPWc263/SnxO24wH0vaRtqmZ8g72SSFVa+6E65bdhSUaIejIDvILaBv+73KdUt7LGKPmqKoftErfP4grQZACnS3zQLXmnMfdzurPkKbBI1PkyT/ase2Czwu5/LwHWdWDcRQD2uZmUjndsKpbR6/xVu5Ry5VLB/ds2BrgjUp5pD+Z0U995X4yVwpr9oCNxR5r1sl+2Wv3jotf19l+safw9XwODQoURKcJiGxtJDymJvVEyl3ZEe1Izwl7SF4UqtboIYt9vEoEIilsuPPDtujnpN5pkY=","layer_level":1},{"id":"fda0598d-7e92-4b8b-be52-92ae63c3cd98","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API客户端","description":"api-client","prompt":"创建API客户端的详细实现文档。说明RESTful API的封装设计、请求配置和响应处理机制。文档化API客户端的错误处理、重试机制和超时控制。解释请求拦截器、响应拦截器和中间件模式。说明API版本管理、URL构建和参数序列化。包含认证头自动添加、状态码处理和错误消息格式化。提供API调用的最佳实践、性能优化和调试技巧。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":5,"progress_status":"completed","dependent_files":"frontend/lib/api.ts","gmt_create":"2026-04-22T18:57:04.217601+08:00","gmt_modified":"2026-04-22T19:24:50.486294+08:00","raw_data":"WikiEncrypted:/umMwKXdJhL9PqhJYRia9MjBtE8cuBSpJq1+zwyrvadwhOTuxc7+NNlJizkRp6kCDsj6HmsrrrEG2WmrNf4m1kFf/yUci2Hny4otqjfpEsOXzmFIxnq13zAZFe1oDyDiHr+shS0DH1omM5IrOroFuNXfBlFlOGXuTKJ3wXXPweq+qAH9QLU237hwRdKdI1UNXoGFfFF9nN8NzOmkwSQ0cRMvswtunfw+yphm0doFqLjrjc0WUZSar4loGeSR6pOSLU8ebi/JkrnwesaWnoYc/1aUJBPdJqVPSJQzjx/Oupuf/R1ihtrn81TMYOUvEaKLk9wVSfSvjh8RGttelGQzTBNJsssgMeqcDh+Qz6r4RJeFKgaRlhn753ONhpYFsHOA/05biB01p6yVuJUR2A3I4tqTlKZ+Xt5K6nvklSqGfR/asdknv3YOkVZOtQxAjyjg/RmmtnslgrEae+k+pBRvgZU23ZT5nZ82LarvwQLYZlu2F16oJjpKEgT3cw98zGHlLEIanqAXIOhT8iR7Fwk6TTKreGcH+oOkFNmbXHWXAD9ixtGbLqoidjzBlLLSR1++hGoabWTFiJX2LKj3lCJ4z30snHEvEL5ruTnKMF+gXM+truHTDsrO5CuaWyGY3WYVTndJKFLi2PQu5FclItm6ykG7LLkMlOXcKTmOrUqOgQhgDR0R7UuPYneG3+8tP49Gar78dBGx+Da8xGwikj9K9OJYAlHpVo05oKo78qku6h+6J2fHgIvIyJPSC88Whc+HpqTBbVMAIjzOQDzTTafDZnEoLWczvFoR5x2aPLnYwXdjyljOhmpXH/bShHcfo1W4KEEzka0Yp+DMZpTiSyhBpA5iLdjZdU9RnTUPTwMtqSXfdbbf0fdgem+z3CsmiuZJVViFNkOfRqL5f7Np4ITC0v2XwLSWr/bC7gbUZiEQdwEr7jwVO1Bk6/MCzvN1G217W7/RUPA4Up/Iu6PRBPcC4dd2r16kpGY4U68Ud7F6iXnc1Twr1Znb+cuTdO4Fu2DQ","layer_level":1},{"id":"7416db23-312f-478d-8883-2fc3c41ac2e8","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"任务调度系统","description":"task-scheduling-system","prompt":"创建任务调度系统的详细文档。解释基于APScheduler的异步任务调度架构,包括调度器配置、任务队列管理和并发控制机制。详细说明查询任务的生命周期管理,包括任务创建、状态跟踪、执行监控和错误恢复。文档化异步任务处理流程,包括任务分发、执行优先级和资源管理。说明调度系统的性能优化策略、监控指标和故障处理机制。提供任务调度的配置选项、扩展方法和调试技巧。","order":6,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,tests/test_scheduler.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:56:47.083393+08:00","gmt_modified":"2026-04-23T15:20:09.061178+08:00","raw_data":"WikiEncrypted:VyywLMbCKto41PC5aDsBo+87rJy1wKhB+t/+dFn1cQKhRzLNGkc+cdUADwdeiVqAIwtiwaq+rwA2WFYQdbiGz8cyKHFmC9lmt3Jas1uZAz4Osy7WTe5xdzE2SEY35xhzdqPvBbNe/p8j0HjSJGFgENGbjEhhukipSO73yvj8CPLzAxa5OEqoQt3uMA0dCSgyFv2LovXFxAXl3U9omZ+jIerOmf0scDYFZ4Cjk4x8Bzb0xm/6wMRJahXUi7eKOQNBfFSlRnxNY+u8u6x0eLR9rZQJsBFNgTapyPe11i341lFAvV8GVMJsgmLfZeTV/A+CJWTGWbc7TTvNnWcbYK7l8zeSZ7dH4rEnOvERyY5kxDrOEwU/Yjdg0OIz0cgmb+dlRmAPiX3OWjxUXJg4aSEFFG16FvCKl2nOFUF8LecaPl1ENKZOzyeeouQpzJp6MwRbCvWKCbKjmM2LofkPlbYC3ljZcmitkM3M0iUQSDo8uwQ71JEBqciChTxdYCFkbs5lTGlaj7NMUVD0hinIuBaEJQ1j0Irfxqf1ncrLdx8ZNQfA0gzLgSYcvydd0BeII/j0Mao27RFzOAqYLYT4lwZn3J2ZefvqYbOF2Sifr+D0ZdG7elOtYhiRAUEHGhPSUWaoI5CpzqRPYnRva8JuLDZi4Kj0EyjpgPrSYN9dp01ryHcTMd7FaHIiskbn258Y9zpaK7mnlVvyKtjxlJL6MtuIV32lhcB+5EW7WH/6QDYQTwSBHw8UP0tyMyNbps8z+8Q5FmgH8vHxFljollei7t8eaPHYkk5rnVsXfTSQ4SjT3Ki6R/yfZ5BEnJidV+OTY4jtwp6TKE+kf6ioudhBQQXHEpufZoZaVaTZXTiIGuNSUBDlZ8hnbIS8ou6QcKMly3uw16qq1jpI+sVrLhWSLFcfRqW774uvsXptcHlY3jyOYYvgNSnLk9DHpURDX2VPzmVnzh4qOFmePV/gjmpSqLQpV1/iNIt9g3DADVd6eBWCjpp7/eefKoA1yLf1v3cLqoz1NFJZDj+xZBAIGNokT1IaiTnENcvwwJWL3xKUl+n4thAe+UgHXKJZ2an3jTF5IKjCZK3wFTIHqnkVBqLbYTnNr8t764mZT1/9wh4OKLf46TVR2knmcx1cuUtGr3Sewy3daul0qF4ixlI8qx00gkAJPhMSgdD9NphN7vd38cFIdIrhJ257ibJH98P6LFTvtBlJtLNk0e8UNLU9gvqtKe+mlotbHy1WlN3l1P02b370hBTcnBA0JVykYqIO2Yux+kvP"},{"id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API接口文档","description":"api-documentation","prompt":"创建GEO平台的完整API接口文档。详细记录所有RESTful API端点,包括HTTP方法、URL模式、请求参数和响应格式。文档化认证接口的JWT令牌管理、用户注册登录和权限验证机制。说明查询管理接口的任务创建、编辑、删除和执行功能。详细描述引用数据接口的数据查询、统计分析和上下文提取功能。文档化报告导出接口的CSV格式生成和数据导出流程。包含错误处理、状态码说明和API使用示例。","order":7,"progress_status":"completed","dependent_files":"backend/app/api/subscriptions.py,backend/app/api/admin.py,backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/services/citation.py,backend/app/api/auth.py,backend/app/api/queries.py,backend/app/api/citations.py,backend/app/api/reports.py,backend/app/api/deps.py","gmt_create":"2026-04-22T18:56:47.083629+08:00","gmt_modified":"2026-04-24T11:02:30.089402+08:00","raw_data":"WikiEncrypted:rEJA+fDSevRLFPlWlcH+C02eArPzlHQTxpYkpRmh+m+CmPwrZOHSqyEVvpFbcfuzlCdXmMyG1qoekj03JLnUhMCX8p4fjuyWVCjGyWgOqZfEYH4zqWamc16YOPdK+sCFQ4QmdrKW6cFcIs/JSz1BcE42L6PRCsFSdjC3x3Ir2kmeZ2xCyI4DTuIg5MWkYlr15jZuzLH5rMyvHib5uxo2LCklVn7i/8Yc6NLOW0AIHuLJGKU9hVU2nes18OolWvbkowwiJKV4MSqSrfUSL53HCd6IbvHajavu3hulkI00H4b/6Rkqq/mkJOEzBVSWXMI2Vj0Ww7mlzTkfkOv9v5Kp1CMC2qupcuFy78Q2J8fnj+tjDbvXOrkAe3LGWo59kGJXRS+LdWUjxsPwbaItkh9PFj2MOBQJ4dj38tLJ7OTH8Zag/VQP1Rr0yLqacQC0kduxAW/GKP5mj949etgdOr5Lsjt2hG9a/1bqVl7DWYX88aeyobv3qSg0/o/486gC040fYXNi3RFhZJev7cFLhxmkWPUFqKblmvIDwS5eDfYnWF4VVACVcqUVKWN/0V1whA2/u83e0nSdQLHU6gs1dAadBeJ0WvtCalaRzumPYSlz4Aw8pywfTE9u5GXpaONFFjCfgFuf6Mm3qpvL8InOKs1DhtGavpj+3P8MaFERk72a/Gb08fD1Ri60LsgMXjD5XdSw7IDRukJVTBRP80/vYYdNlDoeuM6uHvxuORxFCZNsTmC6PSerCo3AGnfpERUDzSV+ejU1fSrOc18pronb4I2lfIHjNpr3mjVLfnNEbsMRu/VHtk9lrPlkd3RxYRlC76W8XAK1cJr8Q6qtOz7qkNAs4W5VZoSO+6QAec2P5ej0aUJ0xR0Z1ZZhFyYPQE0VCrvcKSUJgeHUhcoBWbkPuxmk1l0FC4+Cu8JOksLcMRzb/2trJowZ57fQA7N/3YYOKlKW7wFqNXNJQ2djP2A5WflT9OL22/D0Py4o2wLDr7vtXv/4E2A0YJAPcqdwbeeYHN8Cika4GiA0Z48TomRK5PEPSop0NRekjHc2q3gppQK0+Pwy8GM0JOO04VeLCsbRKwjCrIB9+B9ciiBEDh2F/9+OxmySWZVKQB32NFozE4bT00ufcsFWApvwewZkiqUTWBaDjTrXxm1AnewI+T+/bLaY+m6Lr4yGO7jAuUDYkTSVT+IVNFX9ep2FVdMUqZFYp6+Vukj3nVwL8lRaG8zJaJ5TxxiB7grWdRXzaNT5CJlkTSEdFBkExAkNik1S4Xhfs2uU+BSvjZTzB7gOZKEYhjkV5m707rsT75hYFqeRLdIaCSWxZzHIHHTCxOfrAncP+2EkLHjP8bWAOjhdABT3djMsTSgm15W9NG8oAayRIoAE6M/ZAizrqiaAAKxQFAthKpGNTZZfdHNbxIfhk+D65kW8zTuk1aWN2k1ktFAc/sjQplPFkr/rY9K0PiBMFlXrye60kFAtFxjRpPUbtuRr3sMdJjPiHxB/bIi9XODVl9m7eyjDeTZFKmmxzafzNT9VP+YpBSy4QdKXaZkR219fdyhs52iRnGXP+9Phy6uUEh650InWE9CNFGZMSTRPpUkn9xJq/mVLJ667r9W0/aAs7ETC4g=="},{"id":"fc6f24c3-594e-4153-854f-19250834eeb1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"测试策略","description":"testing-strategy","prompt":"创建GEO项目的测试策略文档。详细说明Pytest测试框架的配置和使用方法,包括测试夹具、模拟对象和测试数据管理。文档化单元测试的实现,包括认证模块、引用引擎、查询处理等功能的测试用例设计。说明集成测试的策略,包括API端到端测试、数据库测试和系统集成测试。提供测试最佳实践,包括测试覆盖率要求、持续集成配置和测试环境管理。包含测试调试技巧和性能测试方法。","order":8,"progress_status":"completed","dependent_files":"test_output.txt,tests/test_business_flow.py,tests/test_scheduler.py,tests/,tests/conftest.py,tests/test_auth.py,tests/test_citation_engine.py,tests/test_citations.py,tests/test_queries.py","gmt_create":"2026-04-22T18:56:47.083879+08:00","gmt_modified":"2026-04-23T21:02:44.23225+08:00","raw_data":"WikiEncrypted:Xd2Zu8BM8p49theGlFJHkHqkA5ycuMpwkltd7rjxfkZm5u2F/OCOa2rxC3NxLrZDZf5D15q4Vh8tHCK9cPrOS/yjJEFoGKYx888+pCfJVQGvOvV8lbxJ/fNWDqo3ccIMDBY5poew3y/74L1tz0L9vjHRBLPVQADCR3UfTk94UBhlYGXamKDS74D8TgPqiuz1dVhmkX95unpFQiGQxCgxeV/sDgwTl7DYpnPy4VqFJbcPHD2Xvv828icOoxqz7hWaOp/65B5Vcn9P4LVk7dQmHzrLBdrDLBe+5Rv6mDD3+Rqrv3ZX+1v7tJ1dnmaQ2ZF8tE9ttI6ENeaFys0BrcucTSrsbSDtmFINzGh/aW0G3Q/YRtNfmkC9t+R8wRSnAgYadYSkUuNTVWQRRs4JxAcn+cHODObsEdp79EwDCqcLktVlpNaLJ//B0sOyLQA741MiLH5iM6tglYaOoQ48Ydyw7Fp5U9agWwgK7yZO7REk4ZB9U+juDzjf+qUHyjIVlXUxJXg7ATsy4euCmDpjyxJGRH7Z89wWkOotsSC3igqSM391kOqbzl9P5ZiruYliru20PndDwtXbJQ0jcvvKJsK3RkIYX0ml7BOL9H7Y16TL1Jwc6DVcRkwWQ4IEKG1fJhqYcb4WI/vPDD1jIhHBe6O5VAZtPPA+SIpYJg8+/qf0FQY73EPqWe0jPuc6I2jyN7UbjUMHRAeb0sVvj18qVYb4E+KKwNZyuAs+0SvTk/nTgqFPdNrOZ923/jnJTNt2Df1p89NDS0NGeHobiC4XD8koxe9vshUUdeDjXIopttcYBg4LcWAudoq8OO07eB6xiqn/MwXPaZySdWrqr3bh2xxxaQPR/NTrfrBkN+81NO784cJEkYHfSfUzIqhLhTTNEQpfl12WDM+GnbHWCcyWuN2dvZ6Op/ZCpLO+cQhZnXFPILnCzFf8DyNrbD3niQYcOC6H1nFlaGSmx57lswjyX14vwqOB+yNR8n+xG1a7JwxscBYaNQG5kvfLaJJKpxIdSB2YIKrIwImPHtzTI1Qahh3MfLtqI99aH9p/1LMaKJQsASKr1Ja1X3dO+ZpIiQRTeDR/jdWnzBA7Hk9SjB6ALHJhLYTutqKVkeIL08U9HNeWn3BFwCthEXMHapg0Vh/guoIq1j28UwzPkqMcSynuv98uyhHfUgRbOWQ9WTDis8gPn2jxpoCZyVCAxOTfF+67GDoTn6smJmqHIkQkMjrxLVZE3FfMtXHAcZ2kG9DC1aLVFNm64bP9X/W11dT6vm5SkabIiu1AzYuZDce+Rbg73WaCMrv4sXmBpNYhYUkLRj4gwNEFSd+eOJ/GS6MZSkA7p6A73OY1PHXlRnFrcLN10/XzFaPAM8L3h4WmqYoxFNJPTx5hRuwX2MfiwZgZlaICfBuO"},{"id":"803bfef4-3985-477e-a61c-915a246d0061","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"部署与运维","description":"deployment-operations","prompt":"创建GEO项目的部署与运维文档。详细说明Docker容器化部署的完整流程,包括镜像构建、容器编排和环境配置。文档化生产环境的部署策略,包括Nginx反向代理配置、SSL证书管理和负载均衡设置。说明监控和日志管理方案,包括应用健康检查、错误追踪和性能监控。提供运维最佳实践,包括备份策略、安全配置和故障恢复流程。包含CI/CD流水线配置和自动化部署方法。","order":9,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:56:47.08417+08:00","gmt_modified":"2026-04-22T19:02:23.851886+08:00","raw_data":"WikiEncrypted:0IKfLNOWe9mZfG1jVts3w2XbjO+yyEmY3ONOjrL5GjA8+3c0QEcD9OcCVHu+1BW/N5NkoQV86wegqQ9ShX8iSWP5bp76U/WBxmHscWo6tU/8QlGuoaRAEg/ev4XsKkgC39pvYnfm60PfrpsE2hL1E2GfNGgG77OCHFDgZXXNbh9eCPmSkW8+YhED55nkyvxbnzr0nBnhsGtTzPUxHW1tar+GAvP539R0R/4mYQI87YJ70yZ7fcsaLwgOXmzP3dVnnmpLv+9t7xJhpCjyQsxfBfLLWBAADnbPD/XDJUZjfKYBtzZr96wOF29GlOAKy0gF60uUu4ldT+fyQn+nYlMXrNBIPA4xv5zs0p3ITXaqvMn5CnUdObefSllD9bB5ZAVzibfAxAovDM6bFfCBg78rOiHHyhVisNUpyQVL18Ac1DA/7UfdJH03ceu0hk7swBM7UlLgBUuU8iZZq8IKLS9Hunf/aF7T2fuFhJB+LGpBGwV+3OqWaT6v4reKhSW8vMM4x8XvLXgDttwPeltWlMknvzqijyjE0V38mue+Fe5fYrBZIK66PxnXrGUJKvZPwyAC/8LX6Hk+M3aBWjL4QkiKpbN2/pXCR6dXuPfbswZ11T0xSYdC8m+8SmC5UAgcryC0PI+ULgqxDhrheiaPIpfOAGnPr19iY2++A+xP/IPZf4L9hg2cNxi5vJ+ws54SmeQDUdbzx15ZECbSbz9xkShlRAYOjuUB9/IpZFt7EqH7sEqsFlbF73qp72JFPp2/QYv9av/WYcw6WVtRJG4TQ/Z9jB+DN6yCeSC6B/CfK05zoF7yrVWkLPiSSVYGDSBndH9EFJEJJvzO27tkS1wZXs4fTTE1StkTjYn8EBSRVvIs3Ywg1+iM2SFYcbn3I6QCeqaXuMJ/yEJikxIeLJGlNjiShYEo2FOMQ/6Xk+TlHkxUTepgnzhxFkPq9S2dqK/ZunroHtiqObkTqfkqta9V4EreMpXtO/FUBsVUrmehzAmO7CQ53L74HnyAqFJYWA/iDUt8rABkFT69QahL9BU4bts3AKhAypInqPXBL+0v0WyatxLd1jURgSq11VX9UBNBi4li3TcoFc9wsZpX3LeH1vNueLQzvssRDfTY9doM+g0rgBXDOO59DyyOKrDDMU5D52k5KI5SJOaWWxEa24TOoTfC79Jpc6tW0zAhdvdLD6u/pfsZd693uN4RM8fMtZPh58w5rcXuEHrhVI/0JThluHDnb6a962K0mt7d1makwsRTPZvpvaTrgiaoByIyOuKY7q1L"},{"id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发指南","description":"development-guide","prompt":"创建GEO项目的开发指南文档。详细说明代码规范和最佳实践,包括Python代码风格、TypeScript类型规范和命名约定。文档化开发流程和工作流,包括Git分支策略、代码审查流程和版本发布管理。说明开发工具的使用方法,包括IDE配置、调试技巧和性能分析工具。提供新功能开发的指导原则,包括模块设计、接口定义和测试要求。包含常见开发问题的解决方案和故障排查方法。","order":10,"progress_status":"completed","dependent_files":"push_script.sh,frontend/tsconfig.json,frontend/tailwind.config.ts,frontend/.eslintrc.json,backend/requirements.txt,CONTRIBUTING.md","gmt_create":"2026-04-22T18:56:47.084469+08:00","gmt_modified":"2026-04-23T21:00:59.749127+08:00","raw_data":"WikiEncrypted:9b1XqHriaqPGsMtQmhzV28eiWwL8soWZUx4jD7Lpj1ZvEeRHqDXnLB57Wv0GJdW0bSai+es/AGcSLV4r5Y1zXQCgYNssGUbbdn66dv22fGk42xijVyio7TzEJPm2vZsrwpJe+/yfqkj5uigIlIv06GRfmEvdn6T8ivaGf4o8qPrbbaCqfb656Ecihx7i5F1ZXK+etNk5HJeheOAvl/WoiZD0TchF59yuuB06Rl/W0/sfm7xUtkC5QYYoo6qYsIuOIE9ynhoHFI2junjkQwS3m3E/W3kKHTNe57a56kaMBo2fa1in+LuWr0jPxfsXJWHwwN47eEs+neAYXoxz+AHzJxrd+FTvW8o+Jr7hmJjODk/1u5VGWqquek2DS33JHThmmD3ant8C85SI0QDd2Rez4xia2mCq+kIzwnOuORyodpDeIHYWrwbL0X6Q4KzwwZKXYBlWZH+PqiovtlIQpZ+FrabfOImECKTIsdYECFDGwvOvZdH09Kmi2TqBszsArbv/apEc8HtRyn3MbxlOmBZ3C86pepDzntKeY8OsRhZv1/EHc12+zlfgBxkzS7g3sZhf01vr2xPsYdFU6Zpts9eWNmMJAthuG+wyeYrGDXuGHQFbXa7Rhz/mWmDKqcUZcrGo2ScQwNuk19uCmQ5x7ZTM1iNSbKYWaJwW4jn9gG8sw9+saye/tFTCyDoaqyyumHT8s/aE3bvalg4fA4AE8RigKIlwzLKW7sZmL8sY6b3PBgIJB054DRRSUF/jEW24wPDgcW29SEG6MwyqEVCpBGvI1t7zhmmM6IRklQNvVzGaoQ5GkTDxAaMh5ULEbqPdmjMJkyTP8xtyLhrJz/UJRuvvFOpf2zyyHg8Do9zNEP/FNUbq2sjjMPwMUwZAVcU2jQvNyiUYJXLvzaYk7fSEr74I3YbU9XE+/dofBpCd8tPG/BmV09UZCVgI3UrSRYd+GcgziKhnbDf/UVR691bhj4lUBtNzyNM2AnUWoQN9IMyjpMEo6EDlTrIL6wqn36aRNqPibx1vbsAdFAwmJQbf0oVZ43AGDJde58EOtIh6QzXdY5yj+UYIl8iCXO0VtnMm79ouguB3g59SOTIbv6X/iFjQ3rvERX6pFPBI9GyKfhKQTwib98D+9pkHnU2n625WeukHx67ieQLvZ7pZLfqMYTEQvo80N0JfbAP4FNz4Mtuc7jpXm2JyV/tAI/Y4Lbx1KMUq2mDsZRamD6HWF61GEGr94VsrM8kFcf2RHb9C6Lt3EuKlasgwJqSnr8iO5oONILiT"},{"id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"扩展与定制","description":"extension-customization","prompt":"创建GEO项目的扩展与定制文档。详细说明系统的扩展机制,包括新增API接口、前端页面扩展和数据模型扩展的方法。文档化配置定制选项,包括环境变量配置、功能开关和性能调优参数。说明第三方集成的扩展方法,包括新AI平台接入、新数据库支持和新认证方式的集成流程。提供插件系统的使用指南和扩展开发的最佳实践。包含系统定制化的案例研究和实施建议。","order":11,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/models/,frontend/components/,backend/app/api/","gmt_create":"2026-04-22T18:56:47.085228+08:00","gmt_modified":"2026-04-22T19:03:46.033162+08:00","raw_data":"WikiEncrypted:9tFZPEMPWdLFkkE2XbXYMuMB8FuOYQ0fj+/JXYKsHGVuXRejugUICkyxL86Ju3MeDs2yZuuby22yn9F5xTbpPvuSC/FoLxV09I2ZpvfpcQFUCVmZyQN67BPwYA36FWIbbHI5AJYWayiJUo+io2WnBda4ESUkmi1Ifq6VpdD6Et8Rw2b8dgDDMxi9XaN9V0JJWAK4CsV0ZYGNAK947J00M9KveVb322Q2MkjA5aw0eylKLH0fzY4qNXNGDmfCOuncuvGiH/5DvAXCDuDLYzVd1AHr/9UgPCvmp017Oo8KijVdD66YD+QM7Rh+24GqNvD5xFbOQGd7ey9Mzs33E6JIrsbUhBvbLJOVlRo0EdScVPZsU4HO6zqDAg0ozD1a5kGX/WxHBvhKBJATucW9vC2XG5g21SjjE6NdebD3z3ZjN+cu8jYHMi1BwWhOmvNRvN8HIGjzntLglg7fNrii0iJXTxpZ8Mbpmu6Tk88oMecsGleuA2xhK1yEWycuQ2dZn5e179BE3mGaSOT0Fvp5yXgL4htvqVTAu4QZ+JFJVk8e4NkI2KaoEgS8vmkD+tvnSal6LUgMzXvRJVj5c7y5LEqxY7QwEbvunmtmHaw9xxVNmfj54tFWSDCSUVCBp+otUfdEq+e6UMOQ64QITUXyYlP+zGW5J0ZWBf9GlU5j70IekNuO3mLp/yU922OD64PhCEL3HOTmAtV1L1vunWchdtvyht6rkYuys0Al1WSGeCmVT23fmJlSuKe++K/qQ/TheLhgA4euY3OnlacLzbia76+B2p4tJY+XvzzDZ5c3M6YdKmW0+iKB+TRJgVz1Q8GpFIzUk/ShBam/TanUxOcC0ci89hjchiYImL1tQeigX4Rgfcn8mXYH956z7eyiSYtqk7uIsQYfiW7tqvcyN0jJpGUVHd9IzvK2NAC+ICHilErsg5hRJ66KFaugTnjd2WoIkU8rktkywDasvD24NZM417z8B8l8uHq9XNcg+2bdPA9hqx5ujEUiGXyWkBNvwCZXg9aL2q+4y5NMoZh6ak8uEjC1kc1S61q2kFyKyIjV7QbCMaHhjnrBnkSg/kV2cGrBPeOqWdtANBw5wZ/OJ38FLWJ5nPOzreTmQ/R6J6YNCfmRPpfpVj0tH0o+0rffNxxXa2TnUbu4OSSLdCljK6CsfuYmBOStwIQtEs8T8/+PsrbQKY9NM1KHqhg5Nk72UNylvGupV/Zccfjg3z78M9uUqtXSOA=="},{"id":"8e3d62e8-ddbe-4820-bc41-7da9e91ea598","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"故障排除与FAQ","description":"troubleshooting-faq","prompt":"创建GEO项目的故障排除与常见问题解答文档。详细列举和解决常见的认证问题、数据库连接问题、API调用问题和性能问题。提供系统监控和诊断的方法,包括健康检查、错误日志分析和性能指标监控。说明调试技巧和工具使用,包括开发环境调试、生产环境问题排查和性能分析方法。包含常见错误代码的含义和解决方案,以及预防性维护的最佳实践。提供紧急情况下的故障恢复流程和应急处理方案。","order":12,"progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,frontend/lib/api.ts,docker-compose.yml","gmt_create":"2026-04-22T18:56:47.085508+08:00","gmt_modified":"2026-04-22T19:04:06.13183+08:00","raw_data":"WikiEncrypted:CaKOW8OSSWs4aEYk06Hu0tuZET5JxbVXxA/4vFailoRiq8l6SCRMdp2PbHfZPheZXyPTAgE3AT8Ce8j9xPOCdJxNKAOstuOjZEIRRi9OOYwoluR4MUnob24X+IyLHwTgsJGf9uPY1LVFTI9RTQt8aG1cBHibaRNEJ8+DVkXJW/EDypOxFpOxDxlaCscMdiPRLwhr9V4vJqWV9j2rk1LjP2/M8SJJQ8hbaDoeLevKdECB+aEw9JrL9ycGW0dhxKxQLf/ril9zNHrvahlSXbVZSZ39dpBl57NdFcFaOYt+paf3O6hv3bCTAKGLTRnYa/IuAZ6Xa7YnhqaGQ684LKCBz6VySRNYVUCEvZotYHf1IQdWOj0zFzR7LEIEikIlZyKak++yTNYfbQyBEzye3g6YCmlh6VaVmtGIRzjOYpu0K1UftNcRa1mWnIMrB/Pqe9DpNTg+Yxo3ZHrPyv3ZAmrd8MqA+T+P+/NerCmFD3dRf94NLPP8KU7in+VSfEjVmdE0N+3OfntU+uvNL/kkOhyWNRUKYKFxbqdwCTKqv3Nchs73XyhfNRP7gPkR/stgnowCRnKWS4ncUEJDZTWVFID52kE8nH7Kq/yuB5bJxFX9AeUUaNSBgvMc5YNkq3vULFEqC1/N0bpU4r9+0/U/BcMktmNrRr1HnOIPl3QzwjIsT3j2lp4UXS3Qm4BZFJsh8MVLfgOIMbO1jbuGCXHl88T/rZOCNwf4q93vWo2HnOxDkbdICWgZ9dinRr85RkFQjNWlXdAk0XG8lQPotwJLvS+ZASOv1aWyL42jk/mTJcOU53PFT5rf3+WpVmhNWQGguZ0l04eubO4Va39c6h/+DNsl0OEAiozIMohEgz77qsD47Kf0KZMLnqL3o30TYXYamX/CP8+epBqSWgmzX/ETrrRl/1/JPkSDc//0VC8UmWBJAsdUdzyQh9v9iQddyIZ4MV1k4MGTJ6GwrUqVTszShZJVG80wDMLQvJGqJ0T5rH1P7kBaJ5nBnth822MBy7B1IhN6nDqtLhOJcqT8Qt6x8ODGFx1QMNBdS4lHq5IcRy+nZKiPP3V7uMuuFQsNNodTRhmNnuAliJACWS89hPiGroan2VkusxIu2DW8wdQ/3Z31mIn4cE3O3+Aq6lO+BEMAuYh5WkOEmGsF3cjX/zPPiuBSP7Vd2a9o6gPA7MBfneMWyqodMp6PKh7EG26gaKUaIGq6VkQobSAVfbLxmfIMW6cZ5STH4U1/A7gV2PeuWzwwEJz7axGVQIJ6A9geQevZvD/cnX6BQBuOMkdAOB6PApCpQA=="}],"wiki_items":[{"catalog_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","title":"项目概述","description":"project-overview","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"34e572eb-6fc8-4de7-8061-63783ef8be24","gmt_create":"2026-04-22T18:58:50.323135+08:00","gmt_modified":"2026-04-24T10:58:35.431256+08:00"},{"catalog_id":"e3ae8925-4862-4280-b85a-0b376841b15e","title":"快速开始","description":"getting-started","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"7f028ad1-e989-43ea-b945-c79c33e6f0e3","gmt_create":"2026-04-22T18:58:54.232866+08:00","gmt_modified":"2026-04-22T18:58:54.238013+08:00"},{"catalog_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","title":"后端系统架构","description":"backend-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","gmt_create":"2026-04-22T18:59:20.999631+08:00","gmt_modified":"2026-04-24T10:58:51.177364+08:00"},{"catalog_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","title":"前端系统架构","description":"frontend-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","gmt_create":"2026-04-22T18:59:54.989699+08:00","gmt_modified":"2026-04-24T11:01:58.108443+08:00"},{"catalog_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","title":"数据库设计","description":"database-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","gmt_create":"2026-04-22T19:00:15.762815+08:00","gmt_modified":"2026-04-24T10:59:38.979212+08:00"},{"catalog_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","title":"任务调度系统","description":"task-scheduling-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","gmt_create":"2026-04-22T19:01:21.979952+08:00","gmt_modified":"2026-04-23T15:20:09.061378+08:00"},{"catalog_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","title":"AI平台集成","description":"ai-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","gmt_create":"2026-04-22T19:01:25.981164+08:00","gmt_modified":"2026-04-23T20:31:36.620216+08:00"},{"catalog_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","title":"API接口文档","description":"api-documentation","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","gmt_create":"2026-04-22T19:01:28.269494+08:00","gmt_modified":"2026-04-24T11:02:30.089537+08:00"},{"catalog_id":"803bfef4-3985-477e-a61c-915a246d0061","title":"部署与运维","description":"deployment-operations","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","gmt_create":"2026-04-22T19:02:23.847103+08:00","gmt_modified":"2026-04-22T19:02:23.852058+08:00"},{"catalog_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","title":"开发指南","description":"development-guide","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"643984fc-5a57-498b-8f25-68cc318d9d82","gmt_create":"2026-04-22T19:02:27.517117+08:00","gmt_modified":"2026-04-23T21:00:59.749244+08:00"},{"catalog_id":"fc6f24c3-594e-4153-854f-19250834eeb1","title":"测试策略","description":"testing-strategy","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","gmt_create":"2026-04-22T19:02:30.709013+08:00","gmt_modified":"2026-04-23T21:02:44.232375+08:00"},{"catalog_id":"7c3e3c0b-5d1f-4d64-99be-668041c6cd9d","title":"核心框架配置","description":"core-framework","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","gmt_create":"2026-04-22T19:03:21.689103+08:00","gmt_modified":"2026-04-22T19:03:21.693211+08:00"},{"catalog_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","title":"扩展与定制","description":"extension-customization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"c5849940-e223-4222-be17-aa0a6cb36bc8","gmt_create":"2026-04-22T19:03:46.027426+08:00","gmt_modified":"2026-04-22T19:03:46.033304+08:00"},{"catalog_id":"8e3d62e8-ddbe-4820-bc41-7da9e91ea598","title":"故障排除与FAQ","description":"troubleshooting-faq","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"85306af2-0edf-42b8-b7ad-c03e769cb1e8","gmt_create":"2026-04-22T19:04:06.127415+08:00","gmt_modified":"2026-04-22T19:04:06.131953+08:00"},{"catalog_id":"bcaa04da-04e3-427f-ba01-847ad657e78a","title":"Next.js应用配置","description":"nextjs-app-config","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","gmt_create":"2026-04-22T19:04:47.356556+08:00","gmt_modified":"2026-04-22T19:04:47.361504+08:00"},{"catalog_id":"9e3d703f-f424-47f4-84df-b99873b93e5a","title":"项目介绍","description":"project-introduction","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2793782c-91c8-4052-b9db-39513426c736","gmt_create":"2026-04-22T19:05:00.372036+08:00","gmt_modified":"2026-04-22T19:05:00.376145+08:00"},{"catalog_id":"a06436ee-1678-4a51-bbf8-b0d0ac3456b9","title":"数据库架构","description":"database-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"d5c75004-b01b-416f-850a-4791c5489a32","gmt_create":"2026-04-22T19:05:13.619093+08:00","gmt_modified":"2026-04-22T19:05:13.624074+08:00"},{"catalog_id":"7fea5a24-e6de-4003-bc70-9dae6d8fdb25","title":"适配器架构设计","description":"adapter-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"37003fc0-1cf5-4264-996b-40807001875f","gmt_create":"2026-04-22T19:06:14.01196+08:00","gmt_modified":"2026-04-22T19:06:14.016291+08:00"},{"catalog_id":"b027f234-4ac5-4d6d-9b38-afc8054325f5","title":"单元测试","description":"unit-testing","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","gmt_create":"2026-04-22T19:06:55.084551+08:00","gmt_modified":"2026-04-22T19:06:55.090188+08:00"},{"catalog_id":"940e5918-1689-4001-a284-44f2de75b8ee","title":"认证接口","description":"authentication-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"7c7564ee-7fe2-4555-8ff0-4ec1b757997a","gmt_create":"2026-04-22T19:07:12.352034+08:00","gmt_modified":"2026-04-22T19:07:12.356599+08:00"},{"catalog_id":"78288302-33bd-44f7-8b29-24f516c8b6bb","title":"调度器设计","description":"scheduler-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","gmt_create":"2026-04-22T19:07:22.166733+08:00","gmt_modified":"2026-04-23T20:33:30.132576+08:00"},{"catalog_id":"6406f42a-e10b-4a2b-84a5-0a21c1c759ea","title":"代码规范","description":"code-standards","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"13c568d2-dfa7-4d1b-81c0-dfef247cbb67","gmt_create":"2026-04-22T19:07:51.271116+08:00","gmt_modified":"2026-04-22T19:07:51.274241+08:00"},{"catalog_id":"a91fff3d-ec5e-43df-8176-22f0084109ef","title":"功能扩展","description":"feature-extension","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"d2c7157d-157f-4990-8f76-11f3ea5435f7","gmt_create":"2026-04-22T19:08:25.13644+08:00","gmt_modified":"2026-04-22T19:08:25.14088+08:00"},{"catalog_id":"e8ec6ac6-ad1a-4332-a7be-727b47d71233","title":"Docker容器化部署","description":"docker-containerization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","gmt_create":"2026-04-22T19:08:34.079807+08:00","gmt_modified":"2026-04-22T19:08:34.084736+08:00"},{"catalog_id":"c19260e2-5163-43d4-b35a-b48aae995f4a","title":"认证系统","description":"authentication-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"df661133-efbf-43fe-97c3-f581c81f47a7","gmt_create":"2026-04-22T19:09:25.676813+08:00","gmt_modified":"2026-04-24T11:02:17.638458+08:00"},{"catalog_id":"9b71fe02-5927-4a19-8db8-66eb129ecd9a","title":"认证系统前端实现","description":"auth-system-frontend","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2b32ec11-d228-42c0-9232-103ba7e44f71","gmt_create":"2026-04-22T19:09:48.743111+08:00","gmt_modified":"2026-04-22T19:09:48.747746+08:00"},{"catalog_id":"b80dc237-1a6a-401f-9f4d-14190edebcdd","title":"技术栈","description":"technology-stack","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"e23bd86e-b4ac-40eb-b1c1-38d929fd5419","gmt_create":"2026-04-22T19:09:54.21211+08:00","gmt_modified":"2026-04-22T19:09:54.216205+08:00"},{"catalog_id":"7e5c3b8e-5aa3-448d-ae52-d5a96a413b0b","title":"表结构设计","description":"table-schema-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","gmt_create":"2026-04-22T19:10:23.573187+08:00","gmt_modified":"2026-04-22T19:10:23.576944+08:00"},{"catalog_id":"cc7a1f1b-c70e-4c61-bfbc-6dc408a12ff2","title":"查询执行流程","description":"query-execution-flow","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2fc79486-ec65-4533-860a-89c8877c2ea0","gmt_create":"2026-04-22T19:11:29.34722+08:00","gmt_modified":"2026-04-22T19:11:29.353951+08:00"},{"catalog_id":"fec685a0-c9bb-4048-baf4-40b56b2aa29c","title":"集成测试","description":"integration-testing","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"8c17b44f-1586-459b-a83d-c9b961cd2142","gmt_create":"2026-04-22T19:12:37.811472+08:00","gmt_modified":"2026-04-22T19:12:37.820956+08:00"},{"catalog_id":"9fe32b83-3697-4939-8b10-524f5ed3e65e","title":"Kimi平台集成","description":"kimi-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2126339b-b0f5-4152-924b-cbe028cd0c39","gmt_create":"2026-04-22T19:12:57.009145+08:00","gmt_modified":"2026-04-23T20:35:18.737804+08:00"},{"catalog_id":"b10c2334-a850-471a-9851-a1c698e3a485","title":"查询管理接口","description":"queries-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","gmt_create":"2026-04-22T19:13:13.111099+08:00","gmt_modified":"2026-04-23T20:33:57.632097+08:00"},{"catalog_id":"0c1d3542-92cf-4796-8dba-82caf2f7b361","title":"开发流程","description":"development-workflow","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"222a9371-45c1-4e0d-b1da-e8ada1c501c2","gmt_create":"2026-04-22T19:13:23.079488+08:00","gmt_modified":"2026-04-22T19:13:23.082539+08:00"},{"catalog_id":"109a8fb1-6619-4bc7-8481-e28cc2127d24","title":"生产环境部署","description":"production-deployment","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"26f80935-eac2-44ee-bcdb-d6a79c537750","gmt_create":"2026-04-22T19:13:58.693673+08:00","gmt_modified":"2026-04-22T19:13:58.69756+08:00"},{"catalog_id":"4d5ac6d7-8812-414b-b8df-68574cc36d7d","title":"配置定制","description":"configuration-customization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"e1e0bd0e-01b3-4543-9781-d9beb32b9a57","gmt_create":"2026-04-22T19:14:17.837895+08:00","gmt_modified":"2026-04-22T19:14:17.84356+08:00"},{"catalog_id":"159f2ccf-71b7-4d1b-a4c4-c15b23a4126e","title":"API接口设计","description":"api-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"11936bb5-374f-40f4-bb53-b75264fc4b9d","gmt_create":"2026-04-22T19:15:14.073829+08:00","gmt_modified":"2026-04-22T19:15:14.079089+08:00"},{"catalog_id":"9cc59a5a-f597-4707-b994-b6c49514d553","title":"页面组件设计","description":"page-components","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","gmt_create":"2026-04-22T19:15:16.958138+08:00","gmt_modified":"2026-04-23T15:19:43.818584+08:00"},{"catalog_id":"f70f5d9b-d7c7-4dc6-b36a-5f4508e6acaa","title":"系统架构","description":"system-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"70b3948e-f456-42d2-b7ad-a0097ad5ee5f","gmt_create":"2026-04-22T19:15:17.448445+08:00","gmt_modified":"2026-04-22T19:15:17.452857+08:00"},{"catalog_id":"816a2805-76c9-4f32-a3cf-96428208081e","title":"数据模型","description":"data-models","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"262a3941-fdc6-46b0-b767-be40aa9d5761","gmt_create":"2026-04-22T19:16:35.087998+08:00","gmt_modified":"2026-04-23T15:21:46.785271+08:00"},{"catalog_id":"64cbb894-755f-47b5-854e-c26c7821e9b2","title":"文心平台集成","description":"wenxin-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","gmt_create":"2026-04-22T19:16:36.921828+08:00","gmt_modified":"2026-04-23T20:31:50.506906+08:00"},{"catalog_id":"412f8cb5-54c1-4f32-8966-fa0e5e75bbca","title":"性能优化","description":"performance-optimization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","gmt_create":"2026-04-22T19:16:37.806188+08:00","gmt_modified":"2026-04-22T19:16:37.81795+08:00"},{"catalog_id":"2f7fa0ab-cd3d-4f45-a1c1-389d5a0c2561","title":"开发工具","description":"development-tools","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"979be617-a83d-4db9-b73e-38581348f8c1","gmt_create":"2026-04-22T19:17:43.348035+08:00","gmt_modified":"2026-04-22T19:17:43.3539+08:00"},{"catalog_id":"40ac97e8-7ef0-4198-82d7-d2e332be9d34","title":"测试最佳实践","description":"test-best-practices","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"05e59a75-d52f-42e1-a924-f6a32f06f2fe","gmt_create":"2026-04-22T19:17:48.811042+08:00","gmt_modified":"2026-04-22T19:17:48.815559+08:00"},{"catalog_id":"41a414d2-e13a-497c-8a03-212624dbf5fe","title":"引用数据接口","description":"citations-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"737f8d6c-bd8f-4c11-b142-71a400423323","gmt_create":"2026-04-22T19:18:18.048509+08:00","gmt_modified":"2026-04-22T19:18:18.055466+08:00"},{"catalog_id":"2713d5c6-c6b0-4a38-83f6-56940c2bf695","title":"监控与日志管理","description":"monitoring-logging","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"eb1288f7-5ea1-413a-8f54-4f870306d14d","gmt_create":"2026-04-22T19:18:41.294736+08:00","gmt_modified":"2026-04-22T19:18:41.773932+08:00"},{"catalog_id":"c8a468af-2982-4d9c-82c0-313b5d2ee89c","title":"第三方集成","description":"third-party-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"e9a02c86-236b-49cb-bbed-9462ee123c04","gmt_create":"2026-04-22T19:19:17.34688+08:00","gmt_modified":"2026-04-22T19:19:17.362503+08:00"},{"catalog_id":"9eee7fab-6cd9-4ef3-9415-2f8137f1d199","title":"数据模型设计","description":"data-models","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"23ad3419-5473-4e2c-ac87-d9715090279d","gmt_create":"2026-04-22T19:19:19.260533+08:00","gmt_modified":"2026-04-22T19:19:19.282116+08:00"},{"catalog_id":"f210509a-2381-46fe-8c22-0ed768e6ca70","title":"数据库迁移","description":"database-migration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"7c0201f7-9e02-4cba-9ee1-81c3477f049a","gmt_create":"2026-04-22T19:20:15.023549+08:00","gmt_modified":"2026-04-22T19:20:15.06665+08:00"},{"catalog_id":"d9e45b2a-6443-4a9b-8ed3-4c3c04773772","title":"UI组件库","description":"ui-component-library","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"760610d4-dff6-4c6d-831f-7c9078db86a6","gmt_create":"2026-04-22T19:20:16.20858+08:00","gmt_modified":"2026-04-23T15:22:23.574113+08:00"},{"catalog_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","title":"核心功能","description":"core-features","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","gmt_create":"2026-04-22T19:20:37.644038+08:00","gmt_modified":"2026-04-22T19:20:37.649918+08:00"},{"catalog_id":"ac0658da-7670-4e41-9e57-02d9d0d50680","title":"报告导出接口","description":"reports-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"ae62f4a8-8840-4c8e-9a42-3373370299ff","gmt_create":"2026-04-22T19:21:24.241821+08:00","gmt_modified":"2026-04-22T19:21:24.246484+08:00"},{"catalog_id":"aad61788-1dc9-4682-b743-47188d7aecb6","title":"引用检测算法","description":"citation-detection-algorithm","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"00359e45-209d-4be3-8795-50dea52bdba1","gmt_create":"2026-04-22T19:21:33.106655+08:00","gmt_modified":"2026-04-22T19:21:33.125906+08:00"},{"catalog_id":"7cb1d921-44ed-4e22-8bf9-baba7ff8b7c7","title":"新功能开发","description":"feature-development","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"422c46b3-e69c-4023-a878-411a48ae182f","gmt_create":"2026-04-22T19:21:46.910999+08:00","gmt_modified":"2026-04-22T19:21:46.916175+08:00"},{"catalog_id":"c45e66b9-1ca0-41da-a796-6b98f394faa1","title":"运维最佳实践","description":"maintenance-operations","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","gmt_create":"2026-04-22T19:22:39.442855+08:00","gmt_modified":"2026-04-22T19:22:39.447035+08:00"},{"catalog_id":"bfca5ffe-8905-4ac2-a0a3-8e4dc43533b1","title":"数据可视化","description":"data-visualization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"a40267bc-925a-4364-a01f-b96d3df60aea","gmt_create":"2026-04-22T19:23:03.398982+08:00","gmt_modified":"2026-04-22T19:23:03.405853+08:00"},{"catalog_id":"05214c1a-d804-4f3c-9048-20ba4de3be0f","title":"引用检测引擎","description":"citation-engine","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"19e75845-5147-4aeb-90be-16f3aa270465","gmt_create":"2026-04-22T19:23:12.049419+08:00","gmt_modified":"2026-04-23T20:33:37.372858+08:00"},{"catalog_id":"b32b024e-2d06-45c8-94c2-a07fd25ab9b3","title":"快速开始","description":"quick-start","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"7e679d62-c415-4d6a-a7e5-d41d00e0ed69","gmt_create":"2026-04-22T19:23:49.794133+08:00","gmt_modified":"2026-04-22T19:23:49.797304+08:00"},{"catalog_id":"850fc702-3eb6-45b4-acd2-ae87fec1f4f1","title":"工作器系统","description":"worker-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"83fe6837-7874-4467-8114-103062f15f58","gmt_create":"2026-04-22T19:24:30.524061+08:00","gmt_modified":"2026-04-22T19:24:30.529283+08:00"},{"catalog_id":"fda0598d-7e92-4b8b-be52-92ae63c3cd98","title":"API客户端","description":"api-client","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"7bd2c461-81b0-48e8-8cb3-b4b14305806d","gmt_create":"2026-04-22T19:24:50.482622+08:00","gmt_modified":"2026-04-22T19:24:50.486476+08:00"},{"catalog_id":"15d6170d-716c-4d2a-833d-81211a59027c","title":"平台适配器扩展指南","description":"platform-adapter-extension","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2632a6f9-774e-4a91-94da-a984bdb20758","gmt_create":"2026-04-22T19:25:18.714623+08:00","gmt_modified":"2026-04-22T19:25:18.720105+08:00"},{"catalog_id":"a232faa5-28b0-4235-8ad4-b082fd226e69","title":"订阅管理系统","description":"subscription-management-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"ec2f1708-d31e-42bb-8959-fa405db7d6da","gmt_create":"2026-04-24T11:04:05.337544+08:00","gmt_modified":"2026-04-24T11:04:05.339776+08:00"},{"catalog_id":"9ac86c99-3b7e-4745-bc95-9586153d616e","title":"管理员仪表板系统","description":"admin-dashboard-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2059d1cd-98a3-4b7f-b29b-69acf8a0d751","gmt_create":"2026-04-24T11:06:01.087669+08:00","gmt_modified":"2026-04-24T11:06:01.089977+08:00"},{"catalog_id":"d54446b1-5984-4fe6-8fc1-ad0322ab7914","title":"安全增强功能","description":"security-enhancements","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"d474a7a6-e056-4456-ba79-4aedbb7add58","gmt_create":"2026-04-24T11:07:19.926098+08:00","gmt_modified":"2026-04-24T11:07:19.927668+08:00"},{"catalog_id":"d645182f-1eaa-4439-854c-0437806ceebb","title":"PDF报告系统","description":"pdf-reporting-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","id":"2d7c030d-7b82-418c-9a16-67b067cac93c","gmt_create":"2026-04-24T11:08:42.186525+08:00","gmt_modified":"2026-04-24T11:08:42.188311+08:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n\n# GEO 平台项目全面分析\n\n## 1. 项目介绍\n\n### 目标与愿景\nGEO 平台是一个基于人工智能技术的学术查询与引用管理系统,旨在为用户提供智能化的品牌引用检测和数据分析服务。该项目通过集成多个AI平台,实现对网络内容中特定品牌引用的自动检测和统计分析。\n\n### 核心目标\n- **智能引用检测**:自动识别网络内容中对特定品牌的引用情况\n- **多平台集成**:支持多个AI平台的数据获取和处理\n- **实时监控**:提供定时查询和实时更新功能\n- **数据可视化**:通过图表展示引用趋势和统计数据\n\n### 目标用户\n- 学术研究人员\n- 市场分析师\n- 品牌监测机构\n- 内容创作者\n\n## 2. 技术架构\n\n### 整体架构设计\n\n```mermaid\ngraph TB\n subgraph \"前端层\"\n FE[Next.js 前端]\n UI[React 组件]\n Auth[认证系统]\n end\n \n subgraph \"后端层\"\n API[FastAPI API]\n WS[工作器]\n SCH[调度器]\n end\n \n subgraph \"数据层\"\n DB[(PostgreSQL)]\n RD[Redis 缓存]\n end\n \n subgraph \"AI平台\"\n WX[Wenxin 平台]\n KM[Kimi 平台]\n end\n \n FE --\u003e API\n UI --\u003e FE\n Auth --\u003e FE\n API --\u003e DB\n API --\u003e RD\n WS --\u003e WX\n WS --\u003e KM\n SCH --\u003e WS\n API --\u003e WS\n```\n\n### 核心设计模式\n- **分层架构**:清晰的前后端分离和业务逻辑分层\n- **异步编程**:基于 asyncio 的高性能异步处理\n- **依赖注入**:通过 FastAPI 的依赖系统管理服务\n- **适配器模式**:统一不同AI平台的接口调用\n\n### 系统关系图\n\n```mermaid\nsequenceDiagram\n participant U as 用户\n participant F as 前端\n participant B as 后端API\n participant S as 调度器\n participant W as 引用引擎\n participant P as AI平台\n \n U-\u003e\u003eF: 发起查询请求\n F-\u003e\u003eB: HTTP请求\n B-\u003e\u003eS: 触发查询任务\n S-\u003e\u003eW: 执行查询\n W-\u003e\u003eP: 调用AI平台\n P--\u003e\u003eW: 返回结果\n W--\u003e\u003eB: 处理后的数据\n B--\u003e\u003eF: 响应结果\n F--\u003e\u003eU: 展示数据\n```\n\n## 3. 关键实现\n\n### 主要入口点\n\n**后端主入口**\n- `backend/app/main.py` - FastAPI 应用主入口,包含路由注册和中间件配置\n\n**前端主入口**\n- `frontend/app/layout.tsx` - Next.js 应用布局组件,包含全局样式和提供者配置\n\n### 核心模块\n\n**数据库配置**\n- `backend/app/database.py` - SQLAlchemy 异步数据库配置和会话管理\n\n**配置管理**\n- `backend/app/config.py` - Pydantic 设置类,管理环境变量和配置参数\n\n**工作器系统**\n- `backend/app/workers/scheduler.py` - APScheduler 定时任务调度器\n- `backend/app/workers/citation_engine.py` - 引用检测引擎核心\n\n**API 路由**\n- `backend/app/api/auth.py` - 用户认证相关接口\n- `backend/app/api/citations.py` - 引用数据相关接口\n- `backend/app/api/queries.py` - 查询任务相关接口\n\n### 配置方法\n\n**Docker 配置**\n- `docker-compose.yml` - 多容器部署配置,包含数据库、缓存和应用服务\n\n**依赖管理**\n- `backend/requirements.txt` - Python 后端依赖包\n- `frontend/package.json` - Node.js 前端依赖包\n\n### 外部依赖\n\n**后端关键技术栈**\n- FastAPI + Uvicorn:高性能异步Web框架\n- SQLAlchemy 2.0:异步ORM框架\n- APScheduler:任务调度框架\n- Redis:缓存和队列存储\n- Playwright:浏览器自动化\n\n**前端关键技术栈**\n- Next.js 14:React 框架\n- Radix UI:可访问性UI组件库\n- Recharts:数据可视化图表\n- Tailwind CSS:CSS框架\n\n### 集成点\n\n**AI平台适配**\n- `backend/app/workers/platforms/kimi.py` - Kimi AI平台适配器\n- `backend/app/workers/platforms/wenxin.py` - 百度文心平台适配器\n\n**认证集成**\n- `frontend/components/providers.tsx` - NextAuth.js 认证提供者\n- `frontend/lib/auth.ts` - 前端认证工具函数\n\n### 组件关系图\n\n```mermaid\ngraph LR\n subgraph \"认证模块\"\n AUTH_API[认证API]\n AUTH_FE[认证前端]\n NEXT_AUTH[NextAuth集成]\n end\n \n subgraph \"查询模块\"\n QUERY_API[查询API]\n QUERY_FE[查询前端]\n SCHEDULER[调度器]\n ENGINE[引用引擎]\n end\n \n subgraph \"数据模块\"\n MODELS[数据模型]\n DB[(数据库)]\n REDIS[(Redis)]\n end\n \n AUTH_API --\u003e MODELS\n QUERY_API --\u003e MODELS\n ENGINE --\u003e MODELS\n AUTH_FE --\u003e AUTH_API\n QUERY_FE --\u003e QUERY_API\n SCHEDULER --\u003e ENGINE\n ENGINE --\u003e DB\n ENGINE --\u003e REDIS\n AUTH_API --\u003e DB\n QUERY_API --\u003e DB\n```\n\n## 4. 核心功能\n\n### 功能概览\n\n**用户管理功能**\n- 用户注册和登录认证\n- JWT 令牌管理和会话维护\n- 用户权限控制\n\n**查询管理功能**\n- 自定义关键词查询\n- 多平台AI数据获取\n- 定时任务调度\n- 查询历史记录\n\n**引用检测功能**\n- 品牌引用自动检测\n- 置信度评分算法\n- 竞争品牌识别\n- 文本上下文提取\n\n**数据分析功能**\n- 引用趋势图表\n- 平台对比分析\n- 统计报表生成\n\n### 实现亮点\n\n**智能匹配算法**\n- `backend/app/workers/citation_engine.py` - 实现精确匹配、别名匹配和模糊匹配三种策略\n- 支持中文和英文混合文本处理\n- 提供置信度评分和位置信息\n\n**异步任务处理**\n- `backend/app/workers/scheduler.py` - 基于 APScheduler 的异步任务调度\n- 支持多平台并发查询\n- 完善的任务状态跟踪\n\n**响应式前端界面**\n- `frontend/app/(dashboard)/` - Next.js App Router 页面组织\n- `frontend/components/charts/` - 数据可视化组件\n- `frontend/components/ui/` - 可复用UI组件库\n\n### 功能架构图\n\n```mermaid\nstateDiagram-v2\n [*] --\u003e 用户认证\n 用户认证 --\u003e 查询管理: 登录成功\n 查询管理 --\u003e 任务调度: 创建查询\n 任务调度 --\u003e 引用检测: 定时触发\n 引用检测 --\u003e 数据处理: 获取AI结果\n 数据处理 --\u003e 结果展示: 处理完成\n 结果展示 --\u003e 查询管理: 新查询\n 结果展示 --\u003e [*]: 退出系统\n \n state 查询管理 {\n [*] --\u003e 创建查询\n 创建查询 --\u003e 编辑查询\n 编辑查询 --\u003e 删除查询\n 删除查询 --\u003e [*]\n }\n \n state 引用检测 {\n [*] --\u003e 平台查询\n 平台查询 --\u003e 品牌匹配\n 品牌匹配 --\u003e 竞争检测\n 竞争检测 --\u003e [*]\n }\n```\n\n## 5. 总结与建议\n\n### 项目架构特点\n\n**架构优势**\n- 清晰的分层设计,前后端职责明确\n- 异步编程模型提升了系统性能\n- 模块化设计便于功能扩展和维护\n- 完善的错误处理和日志记录机制\n\n**技术亮点**\n- 基于现代技术栈的全栈开发\n- 智能算法与工程实践的结合\n- 完整的开发到部署流程\n- 良好的代码组织和文档规范\n\n### 改进建议\n\n**性能优化**\n- 考虑引入连接池优化数据库连接\n- 实现缓存策略减少重复查询\n- 添加限流机制防止API滥用\n\n**功能扩展**\n- 增加更多AI平台支持\n- 实现批量查询功能\n- 添加导出数据功能\n- 增强搜索过滤条件\n\n**代码质量**\n- 完善单元测试覆盖率\n- 添加API文档自动生成\n- 实现更详细的错误处理\n- 优化前端组件复用性\n\n### 下一步发展\n\n**短期目标**\n- 完善用户认证和权限系统\n- 优化引用检测算法准确性\n- 增强前端用户体验\n\n**长期规划**\n- 支持多语言和国际化\n- 实现移动端应用\n- 添加机器学习模型优化\n- 构建开发者API平台\n\nSources:\n- [main.py](backend/app/main.py)\n- [config.py](backend/app/config.py)\n- [database.py](backend/app/database.py)\n- [layout.tsx](frontend/app/layout.tsx)\n- [providers.tsx](frontend/components/providers.tsx)\n- [scheduler.py](backend/app/workers/scheduler.py)\n- [citation_engine.py](backend/app/workers/citation_engine.py)\n- [auth.py](backend/app/api/auth.py)\n- [docker-compose.yml](docker-compose.yml)\n- [requirements.txt](backend/requirements.txt)\n- [package.json](frontend/package.json)\n\n\u003c/blog\u003e","gmt_create":"2026-04-22T18:54:45.079999+08:00","gmt_modified":"2026-04-22T18:54:45.079999+08:00","id":"1e2d007d-9249-436e-8822-c9b1a31580d1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1"},"wiki_readme":{"content":"No readme file","gmt_create":"2026-04-22T18:53:55.057287+08:00","gmt_modified":"2026-04-22T18:53:55.057287+08:00","id":"354aa9f0-35fb-44a7-98d6-034981f130e6","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1"},"wiki_repo":{"id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"GEO","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── .npm-cache/\\n│ ├── _cacache/\\n│ ├── _logs/\\n│ └── _npx/\\n├── .pytest_cache/\\n├── backend/\\n│ ├── alembic/\\n│ │ ├── __pycache__/\\n│ │ ├── versions/\\n│ │ │ ├── __pycache__/\\n│ │ │ └── 488d0bd5ab01_initial_migration.py\\n│ │ ├── README\\n│ │ ├── env.py\\n│ │ └── script.py.mako\\n│ ├── app/\\n│ │ ├── __pycache__/\\n│ │ ├── api/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── __init__.py\\n│ │ │ ├── auth.py\\n│ │ │ ├── citations.py\\n│ │ │ ├── deps.py\\n│ │ │ ├── queries.py\\n│ │ │ └── reports.py\\n│ │ ├── models/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── __init__.py\\n│ │ │ ├── citation_record.py\\n│ │ │ ├── query.py\\n│ │ │ ├── query_task.py\\n│ │ │ ├── subscription.py\\n│ │ │ └── user.py\\n│ │ ├── schemas/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── auth.py\\n│ │ │ ├── citation.py\\n│ │ │ └── query.py\\n│ │ ├── services/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── auth.py\\n│ │ │ ├── citation.py\\n│ │ │ └── query.py\\n│ │ ├── utils/\\n│ │ ├── workers/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── platforms/\\n│ │ │ │ ├── __pycache__/\\n│ │ │ │ ├── base.py\\n│ │ │ │ ├── kimi.py\\n│ │ │ │ └── wenxin.py\\n│ │ │ ├── __init__.py\\n│ │ │ ├── citation_engine.py\\n│ │ │ └── scheduler.py\\n│ │ ├── config.py\\n│ │ ├── database.py\\n│ │ └── main.py\\n│ ├── venv/\\n│ ├── Dockerfile\\n│ ├── alembic.ini\\n│ └── requirements.txt\\n├── docs/\\n├── frontend/\\n│ ├── .next/\\n│ ├── app/\\n│ │ ├── (auth)/\\n│ │ │ ├── login/\\n│ │ │ │ └── page.tsx\\n│ │ │ ├── register/\\n│ │ │ │ └── page.tsx\\n│ │ │ └── layout.tsx\\n│ │ ├── (dashboard)/\\n│ │ │ ├── dashboard/\\n│ │ │ │ ├── citations/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── queries/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── reports/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── settings/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ └── page.tsx\\n│ │ │ └── layout.tsx\\n│ │ ├── api/auth/[...nextauth]/\\n│ │ │ └── route.ts\\n│ │ ├── fonts/\\n│ │ ├── globals.css\\n│ │ ├── layout.tsx\\n│ │ └── page.tsx\\n│ ├── components/\\n│ │ ├── charts/\\n│ │ │ ├── platform-chart.tsx\\n│ │ │ └── trend-chart.tsx\\n│ │ ├── layout/\\n│ │ │ ├── header.tsx\\n│ │ │ └── sidebar.tsx\\n│ │ ├── ui/\\n│ │ │ ├── badge.tsx\\n│ │ │ ├── button.tsx\\n│ │ │ ├── card.tsx\\n│ │ │ ├── dialog.tsx\\n│ │ │ ├── dropdown-menu.tsx\\n│ │ │ ├── input.tsx\\n│ │ │ ├── label.tsx\\n│ │ │ ├── select.tsx\\n│ │ │ ├── table.tsx\\n│ │ │ └── tabs.tsx\\n│ │ └── providers.tsx\\n│ ├── lib/\\n│ │ ├── api.ts\\n│ │ ├── auth.ts\\n│ │ ├── platforms.ts\\n│ │ └── utils.ts\\n│ ├── node_modules/\\n│ ├── types/\\n│ │ └── next-auth.d.ts\\n│ ├── .eslintrc.json\\n│ ├── .gitignore\\n│ ├── Dockerfile\\n│ ├── README.md\\n│ ├── next-env.d.ts\\n│ ├── next.config.mjs\\n│ ├── package-lock.json\\n│ ├── package.json\\n│ ├── postcss.config.mjs\\n│ ├── tailwind.config.ts\\n│ ├── tsconfig.json\\n│ └── tsconfig.tsbuildinfo\\n├── tests/\\n│ ├── __pycache__/\\n│ ├── conftest.py\\n│ ├── test_auth.py\\n│ ├── test_citation_engine.py\\n│ ├── test_citations.py\\n│ └── test_queries.py\\n└── docker-compose.yml\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted: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","recovery_checkpoint":"wiki_generation_completed","last_commit_id":"47879a11f762e40ad2bc967aba5ae76752a794ed","last_commit_update":"2026-04-24T11:08:43.103258+08:00","gmt_create":"2026-04-22T17:58:32.591608+08:00","gmt_modified":"2026-04-24T11:08:43.103259+08:00","extend_info":"{\"language\":\"zh\",\"active\":true,\"branch\":\"main\",\"shareStatus\":\"\",\"server_error_code\":\"\",\"cosy_version\":\"\"}"}} \ No newline at end of file +{"code_snippets":[{"id":"8a466b0c6eac2ccb54c5da7e13854646","path":"frontend/app/layout.tsx","line_range":"1-37","gmt_create":"2026-04-23T15:19:43.759937+08:00","gmt_modified":"2026-04-23T15:19:43.759937+08:00"},{"id":"3bd4eedea376e3a3d9f9fbff4fe27a65","path":"frontend/components/layout/sidebar.tsx","line_range":"1-54","gmt_create":"2026-04-23T15:19:43.760535+08:00","gmt_modified":"2026-04-23T15:19:43.760535+08:00"},{"id":"0d903468b55bdc63cc7e25a87a89c522","path":"frontend/components/layout/header.tsx","line_range":"1-30","gmt_create":"2026-04-23T15:19:43.760868+08:00","gmt_modified":"2026-04-23T15:19:43.760868+08:00"},{"id":"3bab92a09e9fb456e0303bb1e04afc7e","path":"frontend/components/ui/table.tsx","line_range":"1-118","gmt_create":"2026-04-23T15:19:43.762327+08:00","gmt_modified":"2026-04-23T15:19:43.762327+08:00"},{"id":"0eed9f61572209dd754611fc7c690d5a","path":"frontend/components/ui/dialog.tsx","line_range":"1-123","gmt_create":"2026-04-23T15:19:43.762637+08:00","gmt_modified":"2026-04-23T15:19:43.762637+08:00"},{"id":"b7796fc6197ecce5beb461b9466e54a0","path":"frontend/components/charts/trend-chart.tsx","line_range":"1-60","gmt_create":"2026-04-23T15:19:43.762953+08:00","gmt_modified":"2026-04-23T15:19:43.762953+08:00"},{"id":"6b9f52af0b6d78c17ff9bbc42d760ea2","path":"frontend/components/charts/platform-chart.tsx","line_range":"1-68","gmt_create":"2026-04-23T15:19:43.763292+08:00","gmt_modified":"2026-04-23T15:19:43.763292+08:00"},{"id":"a829403082cc3460c01e0110229c53c4","path":"frontend/lib/platforms.ts","line_range":"1-18","gmt_create":"2026-04-23T15:19:43.763596+08:00","gmt_modified":"2026-04-23T15:19:43.763596+08:00"},{"id":"dcfa308ef4ec368c5a51a17acbfc8e2c","path":"frontend/lib/utils.ts","line_range":"1-7","gmt_create":"2026-04-23T15:19:43.763899+08:00","gmt_modified":"2026-04-23T15:19:43.763899+08:00"},{"id":"0f87c8089f548883d056f0a0d79e273f","path":"frontend/lib/api.ts","line_range":"1-79","gmt_create":"2026-04-23T15:19:43.764207+08:00","gmt_modified":"2026-04-23T15:19:43.764207+08:00"},{"id":"9beee1f41fe8f0750fd97155f9d54bbb","path":"frontend/lib/api.ts","line_range":"67-70","gmt_create":"2026-04-23T15:19:43.7681+08:00","gmt_modified":"2026-04-23T15:19:43.7681+08:00"},{"id":"8fe2e22a963442076e1ce16ab777573c","path":"frontend/lib/api.ts","line_range":"56-66","gmt_create":"2026-04-23T15:19:43.769967+08:00","gmt_modified":"2026-04-23T15:19:43.769967+08:00"},{"id":"3124ad882ca2cf8fecb6b93696c7f233","path":"frontend/lib/api.ts","line_range":"72-77","gmt_create":"2026-04-23T15:19:43.77323+08:00","gmt_modified":"2026-04-23T15:19:43.773231+08:00"},{"id":"17a97b4ac37fb67b8eda7ce2887c38e7","path":"frontend/app/layout.tsx","line_range":"17-20","gmt_create":"2026-04-23T15:19:43.777372+08:00","gmt_modified":"2026-04-23T15:19:43.777372+08:00"},{"id":"84cba1e0d516e8c9859402fd5c1bc83c","path":"frontend/lib/api.ts","line_range":"3-40","gmt_create":"2026-04-23T15:19:43.777696+08:00","gmt_modified":"2026-04-23T15:19:43.777696+08:00"},{"id":"b55a164add5a8fec2ef0e489f7234829","path":"backend/app/main.py","line_range":"24-47","gmt_create":"2026-04-23T15:19:45.591156+08:00","gmt_modified":"2026-04-23T15:19:45.591157+08:00"},{"id":"ae9de874df4a46f4197b6c157c25ec6e","path":"backend/app/api/queries.py","line_range":"15-85","gmt_create":"2026-04-23T15:19:45.594458+08:00","gmt_modified":"2026-04-23T15:19:45.594458+08:00"},{"id":"c066a8d4bffabed87a2e38ccad81c107","path":"backend/app/api/citations.py","line_range":"25-77","gmt_create":"2026-04-23T15:19:45.594783+08:00","gmt_modified":"2026-04-23T15:19:45.594783+08:00"},{"id":"177c73dc4e71186d9eaa1157fc0fe97f","path":"backend/app/api/reports.py","line_range":"16-46","gmt_create":"2026-04-23T15:19:45.595098+08:00","gmt_modified":"2026-04-23T15:19:45.595098+08:00"},{"id":"bcdf50f6234651cb9863ab210e6473e5","path":"backend/app/api/deps.py","line_range":"16-42","gmt_create":"2026-04-23T15:19:45.595733+08:00","gmt_modified":"2026-04-23T15:19:45.595733+08:00"},{"id":"6df0277c2486b148fa26c2682dbdaa4c","path":"backend/app/services/auth.py","line_range":"37-68","gmt_create":"2026-04-23T15:19:45.59605+08:00","gmt_modified":"2026-04-23T15:19:45.59605+08:00"},{"id":"5ea5f192d580031ffe57e1582b70c67e","path":"backend/app/services/query.py","line_range":"12-123","gmt_create":"2026-04-23T15:19:45.596359+08:00","gmt_modified":"2026-04-23T15:19:45.596359+08:00"},{"id":"fe4a793f16cd4e12b56253c0a6d53ae0","path":"backend/app/services/citation.py","line_range":"24-359","gmt_create":"2026-04-23T15:19:45.596722+08:00","gmt_modified":"2026-04-23T15:19:45.596723+08:00"},{"id":"9552bd8a528207f18e4f3a1696f26a55","path":"backend/app/api/auth.py","line_range":"13-37","gmt_create":"2026-04-23T15:19:45.597032+08:00","gmt_modified":"2026-04-23T15:19:45.597032+08:00"},{"id":"4aad38dfc00a0877bd965c3d0b3c280c","path":"backend/app/schemas/auth.py","line_range":"7-34","gmt_create":"2026-04-23T15:19:45.598915+08:00","gmt_modified":"2026-04-23T15:19:45.598915+08:00"},{"id":"9b10dac7dbbb1327afc8a525bf4bd0c3","path":"backend/app/services/query.py","line_range":"45-81","gmt_create":"2026-04-23T15:19:45.599689+08:00","gmt_modified":"2026-04-23T15:19:45.599689+08:00"},{"id":"69118807690ef351a9de910414d5e676","path":"backend/app/schemas/query.py","line_range":"11-94","gmt_create":"2026-04-23T15:19:45.6004+08:00","gmt_modified":"2026-04-23T15:19:45.6004+08:00"},{"id":"212d822d207a4c0bd7825bbf20e188e9","path":"backend/app/api/citations.py","line_range":"59-77","gmt_create":"2026-04-23T15:19:45.601069+08:00","gmt_modified":"2026-04-23T15:19:45.601069+08:00"},{"id":"b0777c7da17be89abb333c81c0dcf349","path":"backend/app/services/citation.py","line_range":"204-261","gmt_create":"2026-04-23T15:19:45.601383+08:00","gmt_modified":"2026-04-23T15:19:45.601384+08:00"},{"id":"26288877e8e1f6c4ff5aca12610b0218","path":"backend/app/schemas/citation.py","line_range":"7-50","gmt_create":"2026-04-23T15:19:45.602042+08:00","gmt_modified":"2026-04-23T15:19:45.602042+08:00"},{"id":"56e46969bdb790a5e8f333184b878d6d","path":"backend/app/models/user.py","line_range":"11-41","gmt_create":"2026-04-23T15:19:45.605045+08:00","gmt_modified":"2026-04-23T15:19:45.605046+08:00"},{"id":"4fb8856be3a581fe8303d11b2284ca29","path":"backend/app/models/query.py","line_range":"11-55","gmt_create":"2026-04-23T15:19:45.605965+08:00","gmt_modified":"2026-04-23T15:19:45.605965+08:00"},{"id":"fd541971cebf8a7c167d717f5c5d1ff6","path":"backend/app/models/citation_record.py","line_range":"11-42","gmt_create":"2026-04-23T15:19:45.606627+08:00","gmt_modified":"2026-04-23T15:19:45.606627+08:00"},{"id":"b84f46f058847733347974841f613688","path":"backend/app/models/query_task.py","line_range":"11-39","gmt_create":"2026-04-23T15:19:45.607023+08:00","gmt_modified":"2026-04-23T15:19:45.607023+08:00"},{"id":"1a2657244414b5681afded9565a86422","path":"backend/app/models/user.py","line_range":"35-40","gmt_create":"2026-04-23T15:19:45.60817+08:00","gmt_modified":"2026-04-23T15:19:45.60817+08:00"},{"id":"acd5a29be2bdd4ae251e10ca266ffe13","path":"backend/app/models/query.py","line_range":"43-48","gmt_create":"2026-04-23T15:19:45.608565+08:00","gmt_modified":"2026-04-23T15:19:45.608565+08:00"},{"id":"27a5e2dd1d197b2e3a45be41c57a6183","path":"backend/app/models/citation_record.py","line_range":"35","gmt_create":"2026-04-23T15:19:45.609141+08:00","gmt_modified":"2026-04-23T15:19:45.609141+08:00"},{"id":"c43e8fc0c04c5ed2db7798d99c8c77b8","path":"backend/app/models/query_task.py","line_range":"34","gmt_create":"2026-04-23T15:19:45.609534+08:00","gmt_modified":"2026-04-23T15:19:45.609534+08:00"},{"id":"a50f983ec39bac67dff5df80f6dad837","path":"backend/app/services/query.py","line_range":"59-60","gmt_create":"2026-04-23T15:19:45.61019+08:00","gmt_modified":"2026-04-23T15:19:45.61019+08:00"},{"id":"55f1628f1ab6f323710e367e12146b1a","path":"backend/app/api/citations.py","line_range":"67-71","gmt_create":"2026-04-23T15:19:45.610496+08:00","gmt_modified":"2026-04-23T15:19:45.610496+08:00"},{"id":"096856da621e23e78422a15e2bfce1f1","path":"backend/app/main.py","line_range":"13-22","gmt_create":"2026-04-23T15:20:08.95664+08:00","gmt_modified":"2026-04-23T15:20:08.95664+08:00"},{"id":"e230904202fcf7a861c6f49b84f9f863","path":"backend/app/workers/scheduler.py","line_range":"25-95","gmt_create":"2026-04-23T15:20:08.956979+08:00","gmt_modified":"2026-04-23T15:20:08.956979+08:00"},{"id":"309607c54b12a6340edc086ffb4737c9","path":"backend/app/workers/citation_engine.py","line_range":"148-309","gmt_create":"2026-04-23T15:20:08.957311+08:00","gmt_modified":"2026-04-23T15:20:08.957311+08:00"},{"id":"d7c319a04abbc6704da53107e07dd8e7","path":"backend/app/services/query.py","line_range":"12-130","gmt_create":"2026-04-23T15:20:08.958773+08:00","gmt_modified":"2026-04-23T15:20:08.958773+08:00"},{"id":"9bfc041fe426da2eb78353827e8d9163","path":"backend/app/database.py","line_range":"1-29","gmt_create":"2026-04-23T15:20:08.95909+08:00","gmt_modified":"2026-04-23T15:20:08.95909+08:00"},{"id":"ad67863041d9eea2b0fb542b5aa33aca","path":"backend/app/workers/platforms/base.py","line_range":"4-18","gmt_create":"2026-04-23T15:20:08.959413+08:00","gmt_modified":"2026-04-23T15:20:08.959413+08:00"},{"id":"eecf9581dbaa0a515cf11514175e7ef9","path":"backend/app/workers/platforms/kimi.py","line_range":"11-206","gmt_create":"2026-04-23T15:20:08.959726+08:00","gmt_modified":"2026-04-23T15:20:08.959726+08:00"},{"id":"5563c29185326a59be61ee0a6eec4463","path":"backend/app/workers/platforms/wenxin.py","line_range":"11-205","gmt_create":"2026-04-23T15:20:08.960155+08:00","gmt_modified":"2026-04-23T15:20:08.960155+08:00"},{"id":"2d35e1345d25020f8e7ac1318db06f7b","path":"backend/app/workers/scheduler.py","line_range":"30-90","gmt_create":"2026-04-23T15:20:08.96886+08:00","gmt_modified":"2026-04-23T15:20:08.968861+08:00"},{"id":"91bda120c0ab69e0e7103a1c89c82424","path":"backend/app/workers/scheduler.py","line_range":"95-172","gmt_create":"2026-04-23T15:20:08.969219+08:00","gmt_modified":"2026-04-23T15:20:08.969219+08:00"},{"id":"160b5326537d25444c40a459a01e79c6","path":"backend/app/workers/citation_engine.py","line_range":"159-234","gmt_create":"2026-04-23T15:20:08.969565+08:00","gmt_modified":"2026-04-23T15:20:08.969565+08:00"},{"id":"6712051c987e10a7c26b089063367398","path":"backend/app/models/query.py","line_range":"24-31","gmt_create":"2026-04-23T15:20:08.970051+08:00","gmt_modified":"2026-04-23T15:20:08.970052+08:00"},{"id":"ac5982063da5f04315f3e82a0d653902","path":"backend/app/models/query_task.py","line_range":"24-32","gmt_create":"2026-04-23T15:20:08.970717+08:00","gmt_modified":"2026-04-23T15:20:08.970717+08:00"},{"id":"06ed912983db33bb8aca162fed68282b","path":"backend/app/models/citation_record.py","line_range":"24-29","gmt_create":"2026-04-23T15:20:08.971135+08:00","gmt_modified":"2026-04-23T15:20:08.971135+08:00"},{"id":"b624be78e3bffd876e403cff2557b088","path":"backend/app/workers/citation_engine.py","line_range":"19-120","gmt_create":"2026-04-23T15:20:08.973448+08:00","gmt_modified":"2026-04-23T15:20:08.973448+08:00"},{"id":"40d0b169aad65c8bb38077deb052fc72","path":"backend/app/workers/platforms/kimi.py","line_range":"33-125","gmt_create":"2026-04-23T15:20:08.97414+08:00","gmt_modified":"2026-04-23T15:20:08.97414+08:00"},{"id":"8b5af998852596e1e08b0e0216bc4b93","path":"backend/app/workers/platforms/wenxin.py","line_range":"33-124","gmt_create":"2026-04-23T15:20:08.974449+08:00","gmt_modified":"2026-04-23T15:20:08.974449+08:00"},{"id":"fe70b1fef9f36e73d26d84987e927c7a","path":"backend/app/api/queries.py","line_range":"15-86","gmt_create":"2026-04-23T15:20:08.978743+08:00","gmt_modified":"2026-04-23T15:20:08.978743+08:00"},{"id":"e1d2b027678118df4d0a50ce9269271d","path":"backend/app/workers/scheduler.py","line_range":"42-90","gmt_create":"2026-04-23T15:20:08.982815+08:00","gmt_modified":"2026-04-23T15:20:08.982815+08:00"},{"id":"e79301a4bc26aa6b49f3f52c3182c3f9","path":"backend/app/workers/citation_engine.py","line_range":"175-234","gmt_create":"2026-04-23T15:20:08.983609+08:00","gmt_modified":"2026-04-23T15:20:08.983609+08:00"},{"id":"1e85186eded8743ff5f231df4aa6df3f","path":"backend/app/workers/platforms/kimi.py","line_range":"21-48","gmt_create":"2026-04-23T15:20:08.98454+08:00","gmt_modified":"2026-04-23T15:20:08.98454+08:00"},{"id":"e2b1718570fb714b2f4342221898ab30","path":"backend/app/workers/platforms/wenxin.py","line_range":"21-48","gmt_create":"2026-04-23T15:20:08.985237+08:00","gmt_modified":"2026-04-23T15:20:08.985237+08:00"},{"id":"e4a49039dae40b7433896c81737fcf8c","path":"backend/app/config.py","line_range":"7-14","gmt_create":"2026-04-23T15:20:08.985763+08:00","gmt_modified":"2026-04-23T15:20:08.985763+08:00"},{"id":"2ee31d68c409e96e951f6cfa7027bca7","path":"backend/app/main.py","line_range":"24-42","gmt_create":"2026-04-23T15:20:08.986265+08:00","gmt_modified":"2026-04-23T15:20:08.986265+08:00"},{"id":"79d6e169e36e6b7493898b5f863e07dc","path":"backend/app/workers/citation_engine.py","line_range":"152-157","gmt_create":"2026-04-23T15:20:08.987693+08:00","gmt_modified":"2026-04-23T15:20:08.987693+08:00"},{"id":"1552315d5fb9f6d7aba5f7e8fa93a975","path":"backend/app/database.py","line_range":"6-10","gmt_create":"2026-04-23T15:20:08.988709+08:00","gmt_modified":"2026-04-23T15:20:08.988709+08:00"},{"id":"599cca7536cae4a7e0ae93043c476a7f","path":"tests/test_queries.py","line_range":"10-154","gmt_create":"2026-04-23T15:20:08.989011+08:00","gmt_modified":"2026-04-23T15:20:08.989011+08:00"},{"id":"2ec3d45edd6221e0cedf7f8887fe090d","path":"tests/test_scheduler.py","line_range":"17-123","gmt_create":"2026-04-23T15:20:08.989312+08:00","gmt_modified":"2026-04-23T15:20:08.989312+08:00"},{"id":"4d323bf0aaf4078f09726dc0890e5955","path":"backend/app/models/subscription.py","line_range":"11-37","gmt_create":"2026-04-23T15:21:46.688165+08:00","gmt_modified":"2026-04-23T15:21:46.688166+08:00"},{"id":"4cef9e740b6feb68c6bd22b660c47320","path":"backend/app/services/query.py","line_range":"1-123","gmt_create":"2026-04-23T15:21:46.688903+08:00","gmt_modified":"2026-04-23T15:21:46.688903+08:00"},{"id":"121203f7f9f539ffb1456c3f5cdfd842","path":"backend/app/services/citation.py","line_range":"1-359","gmt_create":"2026-04-23T15:21:46.689338+08:00","gmt_modified":"2026-04-23T15:21:46.689338+08:00"},{"id":"10d1e37bdc9f353c189b7a2fe79dc85e","path":"backend/app/api/queries.py","line_range":"1-86","gmt_create":"2026-04-23T15:21:46.689691+08:00","gmt_modified":"2026-04-23T15:21:46.689691+08:00"},{"id":"cbd0101fa84d957bcb1baaa623c6b31c","path":"backend/app/api/citations.py","line_range":"1-78","gmt_create":"2026-04-23T15:21:46.690036+08:00","gmt_modified":"2026-04-23T15:21:46.690036+08:00"},{"id":"afe4138895492c26aac5c0120ef46cd8","path":"backend/app/models/__init__.py","line_range":"1-14","gmt_create":"2026-04-23T15:21:46.69035+08:00","gmt_modified":"2026-04-23T15:21:46.69035+08:00"},{"id":"4d11ddf7abb8076d81b30c4315786f9a","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"21-128","gmt_create":"2026-04-23T15:21:46.693035+08:00","gmt_modified":"2026-04-23T15:21:46.693035+08:00"},{"id":"e454b4a54500bd81e7599e6ec97bf12b","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"23-37","gmt_create":"2026-04-23T15:21:46.695671+08:00","gmt_modified":"2026-04-23T15:21:46.695671+08:00"},{"id":"1965adf7cfc65447e3c1ae21fbf6d1c5","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"39-59","gmt_create":"2026-04-23T15:21:46.696432+08:00","gmt_modified":"2026-04-23T15:21:46.696432+08:00"},{"id":"c730faefb34bb87c40c5f636b4ff7f41","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"80-94","gmt_create":"2026-04-23T15:21:46.697413+08:00","gmt_modified":"2026-04-23T15:21:46.697413+08:00"},{"id":"b9978c3eccea3ef566b003216e5047af","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"61-78","gmt_create":"2026-04-23T15:21:46.698274+08:00","gmt_modified":"2026-04-23T15:21:46.698274+08:00"},{"id":"eb6ff4361d7413b57f1f70b1ec2f0c94","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"96-111","gmt_create":"2026-04-23T15:21:46.699021+08:00","gmt_modified":"2026-04-23T15:21:46.699021+08:00"},{"id":"f6c9f1b4e8646c366a31426a4537675d","path":"backend/app/models/query_task.py","line_range":"36-38","gmt_create":"2026-04-23T15:21:46.700462+08:00","gmt_modified":"2026-04-23T15:21:46.700462+08:00"},{"id":"a2adbf02c71e4eb2cf1f120e1a2ff517","path":"backend/app/models/citation_record.py","line_range":"37-41","gmt_create":"2026-04-23T15:21:46.70082+08:00","gmt_modified":"2026-04-23T15:21:46.700821+08:00"},{"id":"0907fc2974ec31c23aaaef02076700a1","path":"backend/app/models/user.py","line_range":"25-33","gmt_create":"2026-04-23T15:21:46.702342+08:00","gmt_modified":"2026-04-23T15:21:46.702342+08:00"},{"id":"842f74e2cc054608242e93fbefd96b45","path":"backend/app/models/query.py","line_range":"32-40","gmt_create":"2026-04-23T15:21:46.702652+08:00","gmt_modified":"2026-04-23T15:21:46.702652+08:00"},{"id":"aed9e839038c45e6ce2023c4e05adb76","path":"backend/app/models/query_task.py","line_range":"27-32","gmt_create":"2026-04-23T15:21:46.702999+08:00","gmt_modified":"2026-04-23T15:21:46.703+08:00"},{"id":"2181318c993526c86458f5eef134aed6","path":"backend/app/services/query.py","line_range":"62-77","gmt_create":"2026-04-23T15:21:46.703419+08:00","gmt_modified":"2026-04-23T15:21:46.703419+08:00"},{"id":"a817488dc968d761a8977fb5bb8d01a2","path":"backend/app/services/query.py","line_range":"45-129","gmt_create":"2026-04-23T15:21:46.703795+08:00","gmt_modified":"2026-04-23T15:21:46.703795+08:00"},{"id":"d20fc729a5d3986b1c077f9e07ece9c4","path":"backend/app/config.py","line_range":"7","gmt_create":"2026-04-23T15:21:46.704958+08:00","gmt_modified":"2026-04-23T15:21:46.704958+08:00"},{"id":"ea655c6d147bc98beb42955d437260cc","path":"backend/app/config.py","line_range":"1-23","gmt_create":"2026-04-23T15:21:46.705746+08:00","gmt_modified":"2026-04-23T15:21:46.705746+08:00"},{"id":"37868a5af96edcdad149caf9a184435a","path":"backend/app/api/queries.py","line_range":"42-85","gmt_create":"2026-04-23T15:21:46.706426+08:00","gmt_modified":"2026-04-23T15:21:46.706426+08:00"},{"id":"601b981b00d93b941843f046a163d5a3","path":"backend/app/schemas/query.py","line_range":"18-33","gmt_create":"2026-04-23T15:21:46.706755+08:00","gmt_modified":"2026-04-23T15:21:46.706755+08:00"},{"id":"290df8332b3d104e5ea8d71dc39315b5","path":"tests/conftest.py","line_range":"1-123","gmt_create":"2026-04-23T15:22:15.985975+08:00","gmt_modified":"2026-04-23T15:22:15.985975+08:00"},{"id":"c2747ca16b879bca0f68955534c3c4fc","path":"backend/app/main.py","line_range":"1-48","gmt_create":"2026-04-23T15:22:15.986592+08:00","gmt_modified":"2026-04-23T15:22:15.986592+08:00"},{"id":"76e6c0abb49fec57cac4892837a143c9","path":"backend/app/api/deps.py","line_range":"1-43","gmt_create":"2026-04-23T15:22:15.987077+08:00","gmt_modified":"2026-04-23T15:22:15.987077+08:00"},{"id":"f66d9907b467b110c638bd527efd95c5","path":"backend/app/api/auth.py","line_range":"1-43","gmt_create":"2026-04-23T15:22:15.987417+08:00","gmt_modified":"2026-04-23T15:22:15.987417+08:00"},{"id":"116584ea9162c1bc05911f39f9ef82b6","path":"backend/app/workers/citation_engine.py","line_range":"1-309","gmt_create":"2026-04-23T15:22:15.988451+08:00","gmt_modified":"2026-04-23T15:22:15.988451+08:00"},{"id":"9630036e63fc15cb81b202cf79671aab","path":"backend/app/workers/scheduler.py","line_range":"1-182","gmt_create":"2026-04-23T15:22:15.988885+08:00","gmt_modified":"2026-04-23T15:22:15.988885+08:00"},{"id":"84fbed7d35f7752e2117a74fcaf5f0e9","path":"backend/app/config.py","line_range":"1-17","gmt_create":"2026-04-23T15:22:15.989594+08:00","gmt_modified":"2026-04-23T15:22:15.989594+08:00"},{"id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","path":"tests/conftest.py","line_range":"19-123","gmt_create":"2026-04-23T15:22:15.990689+08:00","gmt_modified":"2026-04-23T15:22:15.990689+08:00"},{"id":"9df233ef1be4b95068ed91bf01083ae7","path":"tests/conftest.py","line_range":"117-123","gmt_create":"2026-04-23T15:22:15.99106+08:00","gmt_modified":"2026-04-23T15:22:15.99106+08:00"},{"id":"6286d4be455dc058c8be2ee4e0d1175a","path":"backend/app/main.py","line_range":"38-42","gmt_create":"2026-04-23T15:22:15.991399+08:00","gmt_modified":"2026-04-23T15:22:15.991399+08:00"},{"id":"069243fafe60a85cf16a0ca40fa07180","path":"backend/app/api/deps.py","line_range":"16-43","gmt_create":"2026-04-23T15:22:15.991722+08:00","gmt_modified":"2026-04-23T15:22:15.991722+08:00"},{"id":"d5a1fb0bd23ce9240fbf79529ef94a45","path":"backend/app/api/auth.py","line_range":"13-43","gmt_create":"2026-04-23T15:22:15.992045+08:00","gmt_modified":"2026-04-23T15:22:15.992045+08:00"},{"id":"735aef72b4fe6ca4f407e69b7dda8b43","path":"backend/app/api/citations.py","line_range":"25-78","gmt_create":"2026-04-23T15:22:15.992721+08:00","gmt_modified":"2026-04-23T15:22:15.992721+08:00"},{"id":"8128dd67cf376d2cadf7c2d3831c380a","path":"backend/app/database.py","line_range":"23-29","gmt_create":"2026-04-23T15:22:15.993159+08:00","gmt_modified":"2026-04-23T15:22:15.993159+08:00"},{"id":"1721defc3d6206478d3c0692cc821761","path":"tests/test_auth.py","line_range":"25-104","gmt_create":"2026-04-23T15:22:15.9936+08:00","gmt_modified":"2026-04-23T15:22:15.9936+08:00"},{"id":"753a437d837246ead62b0e16c6331284","path":"backend/app/services/auth.py","line_range":"37-69","gmt_create":"2026-04-23T15:22:15.994329+08:00","gmt_modified":"2026-04-23T15:22:15.994329+08:00"},{"id":"d820e2daf2ea133a7aa17cdc475e44a4","path":"tests/test_auth.py","line_range":"1-104","gmt_create":"2026-04-23T15:22:15.99504+08:00","gmt_modified":"2026-04-23T15:22:15.99504+08:00"},{"id":"1a439c5fed6cfd188c646e1614d56371","path":"backend/app/services/auth.py","line_range":"1-69","gmt_create":"2026-04-23T15:22:15.995715+08:00","gmt_modified":"2026-04-23T15:22:15.995715+08:00"},{"id":"5c67e2f70283956b2d29a3c1443eb514","path":"backend/app/workers/citation_engine.py","line_range":"122-146","gmt_create":"2026-04-23T15:22:15.996787+08:00","gmt_modified":"2026-04-23T15:22:15.996787+08:00"},{"id":"a57acd9da5287c915ac823784a409292","path":"tests/test_citation_engine.py","line_range":"1-127","gmt_create":"2026-04-23T15:22:15.99744+08:00","gmt_modified":"2026-04-23T15:22:15.99744+08:00"},{"id":"2a4f741f31f62dce8ad63be2e831f520","path":"tests/test_citations.py","line_range":"23-93","gmt_create":"2026-04-23T15:22:15.998141+08:00","gmt_modified":"2026-04-23T15:22:15.998141+08:00"},{"id":"692ac240965eff7e66945aa3c4c270f7","path":"tests/test_citations.py","line_range":"1-93","gmt_create":"2026-04-23T15:22:15.998797+08:00","gmt_modified":"2026-04-23T15:22:15.998797+08:00"},{"id":"32a0a52faca2d8d488e49c63c86075b1","path":"tests/test_queries.py","line_range":"29-154","gmt_create":"2026-04-23T15:22:15.999443+08:00","gmt_modified":"2026-04-23T15:22:15.999444+08:00"},{"id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","path":"tests/test_queries.py","line_range":"1-154","gmt_create":"2026-04-23T15:22:16.000539+08:00","gmt_modified":"2026-04-23T15:22:16.000539+08:00"},{"id":"3a6e1b738967bf8cc651e57f48e2e126","path":"tests/test_business_flow.py","line_range":"83-126","gmt_create":"2026-04-23T15:22:16.00171+08:00","gmt_modified":"2026-04-23T15:22:16.00171+08:00"},{"id":"b1afd377757f1d0e9bdf87edfff3ad88","path":"tests/test_business_flow.py","line_range":"131-186","gmt_create":"2026-04-23T15:22:16.002219+08:00","gmt_modified":"2026-04-23T15:22:16.002219+08:00"},{"id":"de05ec7eed033e432991e5a88e1b5a06","path":"tests/test_business_flow.py","line_range":"192-222","gmt_create":"2026-04-23T15:22:16.002653+08:00","gmt_modified":"2026-04-23T15:22:16.002653+08:00"},{"id":"7fd61a451248b6b129299d6246f711c7","path":"tests/test_business_flow.py","line_range":"228-296","gmt_create":"2026-04-23T15:22:16.003121+08:00","gmt_modified":"2026-04-23T15:22:16.003121+08:00"},{"id":"53eedffff456a566fa7b0cecc7169f56","path":"tests/test_business_flow.py","line_range":"1-441","gmt_create":"2026-04-23T15:22:16.003614+08:00","gmt_modified":"2026-04-23T15:22:16.003615+08:00"},{"id":"906f7a8288e38d4244211f3f538fe7b6","path":"backend/app/workers/scheduler.py","line_range":"27-182","gmt_create":"2026-04-23T15:22:16.004044+08:00","gmt_modified":"2026-04-23T15:22:16.004044+08:00"},{"id":"1647ee2066de2ae59ba8cf88e33c5e02","path":"tests/test_scheduler.py","line_range":"1-123","gmt_create":"2026-04-23T15:22:16.004461+08:00","gmt_modified":"2026-04-23T15:22:16.004461+08:00"},{"id":"fd18328b6582e68c30b130b912891992","path":"frontend/components/providers.tsx","line_range":"1-9","gmt_create":"2026-04-23T15:22:23.501815+08:00","gmt_modified":"2026-04-23T15:22:23.501815+08:00"},{"id":"71a37a516437e94fd82a87efc70a3f16","path":"frontend/package.json","line_range":"1-40","gmt_create":"2026-04-23T15:22:23.503888+08:00","gmt_modified":"2026-04-23T15:22:23.503888+08:00"},{"id":"89d70e5f89be23a229e3ee59982b8e6e","path":"frontend/tailwind.config.ts","line_range":"1-57","gmt_create":"2026-04-23T15:22:23.504853+08:00","gmt_modified":"2026-04-23T15:22:23.504853+08:00"},{"id":"95be577a89fbeb02578e4c3718c6ec86","path":"frontend/components/ui/button.tsx","line_range":"1-57","gmt_create":"2026-04-23T15:22:23.505579+08:00","gmt_modified":"2026-04-23T15:22:23.505579+08:00"},{"id":"607bb628918a7a5d54cbf74763f94d07","path":"frontend/components/ui/input.tsx","line_range":"1-23","gmt_create":"2026-04-23T15:22:23.506257+08:00","gmt_modified":"2026-04-23T15:22:23.506257+08:00"},{"id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","path":"frontend/components/ui/select.tsx","line_range":"1-161","gmt_create":"2026-04-23T15:22:23.507044+08:00","gmt_modified":"2026-04-23T15:22:23.507044+08:00"},{"id":"ad6ff021b2126ad5c42323305eb6d8b0","path":"frontend/components/ui/dropdown-menu.tsx","line_range":"1-201","gmt_create":"2026-04-23T15:22:23.507926+08:00","gmt_modified":"2026-04-23T15:22:23.507926+08:00"},{"id":"a85f004dca63614b4e734ba63b45ef9e","path":"frontend/components/ui/card.tsx","line_range":"1-80","gmt_create":"2026-04-23T15:22:23.508411+08:00","gmt_modified":"2026-04-23T15:22:23.508411+08:00"},{"id":"bd3042a8d9b602334720b0d7b4e8ab3d","path":"frontend/components/ui/tabs.tsx","line_range":"1-56","gmt_create":"2026-04-23T15:22:23.509355+08:00","gmt_modified":"2026-04-23T15:22:23.509355+08:00"},{"id":"379443f450513b5492e2d9d5fca94a42","path":"frontend/components/ui/label.tsx","line_range":"1-27","gmt_create":"2026-04-23T15:22:23.509832+08:00","gmt_modified":"2026-04-23T15:22:23.509832+08:00"},{"id":"4aa6ad434a73143bb7a2072124f63be0","path":"frontend/components/ui/badge.tsx","line_range":"1-37","gmt_create":"2026-04-23T15:22:23.510286+08:00","gmt_modified":"2026-04-23T15:22:23.510286+08:00"},{"id":"c45dbdda70a8b9f02b52af4991644d0b","path":"frontend/package.json","line_range":"11-27","gmt_create":"2026-04-23T15:22:23.511056+08:00","gmt_modified":"2026-04-23T15:22:23.511056+08:00"},{"id":"6ac6943c93570294e4fb15a862be2616","path":"frontend/components/ui/button.tsx","line_range":"36-54","gmt_create":"2026-04-23T15:22:23.51229+08:00","gmt_modified":"2026-04-23T15:22:23.51229+08:00"},{"id":"4bfb5059c685e9878aed64cb5347ccec","path":"frontend/components/ui/dialog.tsx","line_range":"9-54","gmt_create":"2026-04-23T15:22:23.513266+08:00","gmt_modified":"2026-04-23T15:22:23.513266+08:00"},{"id":"0af48b69fe8fb9e480fa1656f36a4330","path":"frontend/components/ui/dropdown-menu.tsx","line_range":"21-75","gmt_create":"2026-04-23T15:22:23.514127+08:00","gmt_modified":"2026-04-23T15:22:23.514127+08:00"},{"id":"09971e31ab658e119d4c0ad948282107","path":"frontend/components/ui/select.tsx","line_range":"15-100","gmt_create":"2026-04-23T15:22:23.514956+08:00","gmt_modified":"2026-04-23T15:22:23.514956+08:00"},{"id":"31aa8777de6043883950d2668094e388","path":"frontend/components/ui/table.tsx","line_range":"5-106","gmt_create":"2026-04-23T15:22:23.515769+08:00","gmt_modified":"2026-04-23T15:22:23.515769+08:00"},{"id":"28baf3cedb89a21c6d542b7ce2439b24","path":"frontend/components/ui/tabs.tsx","line_range":"8-53","gmt_create":"2026-04-23T15:22:23.516573+08:00","gmt_modified":"2026-04-23T15:22:23.516573+08:00"},{"id":"28b0f4797c6084272244175a24b961cb","path":"frontend/components/ui/card.tsx","line_range":"5-77","gmt_create":"2026-04-23T15:22:23.518527+08:00","gmt_modified":"2026-04-23T15:22:23.518527+08:00"},{"id":"a6e0b3fa65906c3c3cd88707e1d40059","path":"frontend/components/ui/label.tsx","line_range":"9-23","gmt_create":"2026-04-23T15:22:23.520181+08:00","gmt_modified":"2026-04-23T15:22:23.520181+08:00"},{"id":"9a909775022010b4686c2b00cdf1c165","path":"frontend/components/ui/badge.tsx","line_range":"6-34","gmt_create":"2026-04-23T15:22:23.521343+08:00","gmt_modified":"2026-04-23T15:22:23.521343+08:00"},{"id":"ce1cd184945ae56cf63f55168afd8050","path":"frontend/components/ui/dialog.tsx","line_range":"47-50","gmt_create":"2026-04-23T15:22:23.523823+08:00","gmt_modified":"2026-04-23T15:22:23.523823+08:00"},{"id":"4a2a06e1efcbc85deaa013dca155f20c","path":"frontend/tailwind.config.ts","line_range":"10-54","gmt_create":"2026-04-23T15:22:23.524333+08:00","gmt_modified":"2026-04-23T15:22:23.524333+08:00"},{"id":"8b00ea4aba57ea6ed982287fb7840805","path":"frontend/lib/utils.ts","line_range":"4-6","gmt_create":"2026-04-23T15:22:23.524876+08:00","gmt_modified":"2026-04-23T15:22:23.524876+08:00"},{"id":"7c0831c17e8c65eaed9511e17ed2a2ef","path":"backend/app/services/citation.py","line_range":"1-269","gmt_create":"2026-04-23T20:31:36.482111+08:00","gmt_modified":"2026-04-23T20:31:36.482111+08:00"},{"id":"71f98c8993fb42b108e34a554247869b","path":"backend/app/workers/scheduler.py","line_range":"1-95","gmt_create":"2026-04-23T20:31:36.482732+08:00","gmt_modified":"2026-04-23T20:31:36.482732+08:00"},{"id":"8d5aac2ae0671f05d7c0807ba9296cdf","path":"backend/app/workers/citation_engine.py","line_range":"1-330","gmt_create":"2026-04-23T20:31:36.4831+08:00","gmt_modified":"2026-04-23T20:31:36.4831+08:00"},{"id":"debd789847d1eed2d54198772edf68a2","path":"backend/app/workers/platforms/tongyi.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.483423+08:00","gmt_modified":"2026-04-23T20:31:36.483423+08:00"},{"id":"3bde521d18cc7221ae2f14637e163aac","path":"backend/app/workers/platforms/doubao.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.483821+08:00","gmt_modified":"2026-04-23T20:31:36.483821+08:00"},{"id":"c26862d9e0fc878b51a2668cfd2ec827","path":"backend/app/workers/platforms/qingyan.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.484113+08:00","gmt_modified":"2026-04-23T20:31:36.484114+08:00"},{"id":"0fcc9c2e0d33b887c5f18a3807b64a1e","path":"backend/app/workers/platforms/tiangong.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.484512+08:00","gmt_modified":"2026-04-23T20:31:36.484512+08:00"},{"id":"a4baa2444208b3f9a3f42bc492038207","path":"backend/app/workers/platforms/xinghuo.py","line_range":"1-38","gmt_create":"2026-04-23T20:31:36.485041+08:00","gmt_modified":"2026-04-23T20:31:36.485041+08:00"},{"id":"9f82f6d82bf914a608d6afa3d9854abf","path":"backend/app/workers/platforms/search_engine.py","line_range":"1-174","gmt_create":"2026-04-23T20:31:36.485492+08:00","gmt_modified":"2026-04-23T20:31:36.485492+08:00"},{"id":"6281fff17a86ec1895c64d87c2ae7fb1","path":"backend/app/models/query.py","line_range":"1-55","gmt_create":"2026-04-23T20:31:36.486251+08:00","gmt_modified":"2026-04-23T20:31:36.486251+08:00"},{"id":"943c18db69a04b3137fba4cebcfea87e","path":"backend/app/models/citation_record.py","line_range":"1-42","gmt_create":"2026-04-23T20:31:36.48687+08:00","gmt_modified":"2026-04-23T20:31:36.48687+08:00"},{"id":"6628e006b8e5ca16160743528b6b0506","path":"backend/app/models/query_task.py","line_range":"1-39","gmt_create":"2026-04-23T20:31:36.487305+08:00","gmt_modified":"2026-04-23T20:31:36.487305+08:00"},{"id":"72a110dca58d8152758e2fdab4e94761","path":"backend/app/workers/platforms/base.py","line_range":"1-18","gmt_create":"2026-04-23T20:31:36.490327+08:00","gmt_modified":"2026-04-23T20:31:36.490328+08:00"},{"id":"300e43c7a648440163f81039eaa47b5a","path":"frontend/lib/platforms.ts","line_range":"1-24","gmt_create":"2026-04-23T20:31:36.494718+08:00","gmt_modified":"2026-04-23T20:31:36.494718+08:00"},{"id":"caf1970ded8fc5d3921005e166e2100b","path":"backend/app/api/citations.py","line_range":"59-78","gmt_create":"2026-04-23T20:31:36.499676+08:00","gmt_modified":"2026-04-23T20:31:36.499677+08:00"},{"id":"4ded871d02b8119cdd985de8b220b084","path":"backend/app/services/citation.py","line_range":"204-234","gmt_create":"2026-04-23T20:31:36.500626+08:00","gmt_modified":"2026-04-23T20:31:36.500626+08:00"},{"id":"448970b02d89d5e1576f70bdb0063363","path":"backend/app/workers/scheduler.py","line_range":"51-84","gmt_create":"2026-04-23T20:31:36.501136+08:00","gmt_modified":"2026-04-23T20:31:36.501136+08:00"},{"id":"362d22f423631cda39404660b3317a2f","path":"backend/app/workers/citation_engine.py","line_range":"177-254","gmt_create":"2026-04-23T20:31:36.501596+08:00","gmt_modified":"2026-04-23T20:31:36.501596+08:00"},{"id":"b475ff5225ac403c7fcf3dd7e14cbac6","path":"backend/app/workers/platforms/tongyi.py","line_range":"16-33","gmt_create":"2026-04-23T20:31:36.502032+08:00","gmt_modified":"2026-04-23T20:31:36.502032+08:00"},{"id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","path":"backend/app/workers/platforms/search_engine.py","line_range":"163-174","gmt_create":"2026-04-23T20:31:36.502504+08:00","gmt_modified":"2026-04-23T20:31:36.502504+08:00"},{"id":"75c6ab0599d304bf36d290d4143d3d2f","path":"backend/app/models/query.py","line_range":"29-31","gmt_create":"2026-04-23T20:31:36.502934+08:00","gmt_modified":"2026-04-23T20:31:36.502934+08:00"},{"id":"2a6780838f1415dcb7d0fa611f64cee7","path":"backend/app/workers/platforms/base.py","line_range":"4-17","gmt_create":"2026-04-23T20:31:36.504228+08:00","gmt_modified":"2026-04-23T20:31:36.504228+08:00"},{"id":"c5ae7697193b2b93425ff25d2d7d54a9","path":"backend/app/workers/platforms/tongyi.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505069+08:00","gmt_modified":"2026-04-23T20:31:36.505069+08:00"},{"id":"aa8c3fa3bc509dafe64d113bdd09eafa","path":"backend/app/workers/platforms/doubao.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505502+08:00","gmt_modified":"2026-04-23T20:31:36.505503+08:00"},{"id":"eabb031e538ea62cab69b01368740d20","path":"backend/app/workers/platforms/qingyan.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.505932+08:00","gmt_modified":"2026-04-23T20:31:36.505932+08:00"},{"id":"b1c09e372a63e9854886adaea1663bea","path":"backend/app/workers/platforms/tiangong.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.50633+08:00","gmt_modified":"2026-04-23T20:31:36.50633+08:00"},{"id":"79793bcd507f9d287d19014b60d963d3","path":"backend/app/workers/platforms/xinghuo.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:36.506717+08:00","gmt_modified":"2026-04-23T20:31:36.506717+08:00"},{"id":"102223dd13475177a1ade8b9be14fbd1","path":"backend/app/workers/platforms/search_engine.py","line_range":"79-144","gmt_create":"2026-04-23T20:31:36.509667+08:00","gmt_modified":"2026-04-23T20:31:36.509667+08:00"},{"id":"8565f299083b4dcba5a328c947f06fee","path":"backend/app/workers/citation_engine.py","line_range":"256-287","gmt_create":"2026-04-23T20:31:36.512515+08:00","gmt_modified":"2026-04-23T20:31:36.512515+08:00"},{"id":"8af91caf063c12c8236f9675769ce4a1","path":"tests/test_citation_engine.py","line_range":"1-54","gmt_create":"2026-04-23T20:31:36.51401+08:00","gmt_modified":"2026-04-23T20:31:36.51401+08:00"},{"id":"005172b71dc742cf6803c5eb0185091e","path":"backend/requirements.txt","line_range":"1-36","gmt_create":"2026-04-23T20:31:36.516249+08:00","gmt_modified":"2026-04-23T20:31:36.516249+08:00"},{"id":"b55cc5936c299f819b57b899858438e6","path":"backend/app/workers/platforms/search_engine.py","line_range":"139-144","gmt_create":"2026-04-23T20:31:36.518228+08:00","gmt_modified":"2026-04-23T20:31:36.518228+08:00"},{"id":"384b1939e53970ce7ae75d241a49da5f","path":"backend/app/workers/platforms/tongyi.py","line_range":"22-29","gmt_create":"2026-04-23T20:31:36.518493+08:00","gmt_modified":"2026-04-23T20:31:36.518493+08:00"},{"id":"f096aa3ea82e9fa625a9acb1309b4c50","path":"backend/app/workers/citation_engine.py","line_range":"231-247","gmt_create":"2026-04-23T20:31:36.518795+08:00","gmt_modified":"2026-04-23T20:31:36.518795+08:00"},{"id":"15b8ebf74b0a5dfac58024d323ca8d0a","path":"backend/app/workers/citation_engine.py","line_range":"164-175","gmt_create":"2026-04-23T20:31:36.519395+08:00","gmt_modified":"2026-04-23T20:31:36.519395+08:00"},{"id":"bcfade20d923c8efa713808ca9af94ca","path":"backend/app/workers/platforms/wenxin.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:50.45294+08:00","gmt_modified":"2026-04-23T20:31:50.45294+08:00"},{"id":"ca7e1232fbba5fb75e04ab8e491bfbd1","path":"backend/app/workers/platforms/kimi.py","line_range":"10-38","gmt_create":"2026-04-23T20:31:50.453339+08:00","gmt_modified":"2026-04-23T20:31:50.453339+08:00"},{"id":"9720b93ed7247efb685e2825e5f964bf","path":"backend/app/workers/citation_engine.py","line_range":"161-176","gmt_create":"2026-04-23T20:31:50.454207+08:00","gmt_modified":"2026-04-23T20:31:50.454207+08:00"},{"id":"0d226400124ba891a46f59c36781ccd8","path":"backend/app/config.py","line_range":"9-23","gmt_create":"2026-04-23T20:31:50.454503+08:00","gmt_modified":"2026-04-23T20:31:50.454503+08:00"},{"id":"412695e5de2014514a8f62f98c573656","path":"backend/Dockerfile","line_range":"1-41","gmt_create":"2026-04-23T20:31:50.454798+08:00","gmt_modified":"2026-04-23T20:31:50.454798+08:00"},{"id":"485e15eb30a5b08da38a628c9dd5053e","path":"backend/app/workers/platforms/search_engine.py","line_range":"16-77","gmt_create":"2026-04-23T20:31:50.459138+08:00","gmt_modified":"2026-04-23T20:31:50.459138+08:00"},{"id":"77158a6f887e224a03552893bfec7c92","path":"backend/app/workers/platforms/wenxin.py","line_range":"16-33","gmt_create":"2026-04-23T20:31:50.461662+08:00","gmt_modified":"2026-04-23T20:31:50.461662+08:00"},{"id":"5c3f336b5a7b4af4cc2f2ac183539218","path":"backend/app/workers/platforms/search_engine.py","line_range":"79-145","gmt_create":"2026-04-23T20:31:50.464823+08:00","gmt_modified":"2026-04-23T20:31:50.464823+08:00"},{"id":"3894c1ed9dca2ebf2359f40ebdb1959e","path":"backend/app/workers/platforms/search_engine.py","line_range":"147-174","gmt_create":"2026-04-23T20:31:50.465221+08:00","gmt_modified":"2026-04-23T20:31:50.465221+08:00"},{"id":"e27bcba24aaadeec1922d2b4e5b8386b","path":"backend/app/api/queries.py","line_range":"1-109","gmt_create":"2026-04-23T20:31:50.46721+08:00","gmt_modified":"2026-04-23T20:31:50.46721+08:00"},{"id":"5f893f5078aa8e549284feb057aa45da","path":"backend/app/workers/platforms/wenxin.py","line_range":"16-29","gmt_create":"2026-04-23T20:31:50.469467+08:00","gmt_modified":"2026-04-23T20:31:50.469467+08:00"},{"id":"e0b68d2d24760689a0f4f00dfee5f9f2","path":"backend/app/workers/platforms/search_engine.py","line_range":"28-76","gmt_create":"2026-04-23T20:31:50.470319+08:00","gmt_modified":"2026-04-23T20:31:50.470319+08:00"},{"id":"e9b98ae83632342d8e06cde39e9c9462","path":"backend/app/workers/platforms/search_engine.py","line_range":"105-137","gmt_create":"2026-04-23T20:31:50.470672+08:00","gmt_modified":"2026-04-23T20:31:50.470672+08:00"},{"id":"c86edb7a95fbe4b431ac65a0e2b8636e","path":"backend/app/api/queries.py","line_range":"90-109","gmt_create":"2026-04-23T20:31:50.471824+08:00","gmt_modified":"2026-04-23T20:31:50.471825+08:00"},{"id":"6e054d9a78c0c8c9da8dec4c4bda62ab","path":"backend/app/database.py","line_range":"6-28","gmt_create":"2026-04-23T20:33:29.972803+08:00","gmt_modified":"2026-04-23T20:33:29.972803+08:00"},{"id":"9c16a069e5154660bfdfa48f3518fc6a","path":"backend/app/models/query_task.py","line_range":"11-38","gmt_create":"2026-04-23T20:33:29.980385+08:00","gmt_modified":"2026-04-23T20:33:29.980385+08:00"},{"id":"a4918fcbd21492ad996d7f5496f03a4b","path":"backend/app/workers/platforms/kimi.py","line_range":"33-48","gmt_create":"2026-04-23T20:33:29.982795+08:00","gmt_modified":"2026-04-23T20:33:29.982795+08:00"},{"id":"bc38d046b4b1410ae2165cee2272839e","path":"backend/app/workers/platforms/wenxin.py","line_range":"33-48","gmt_create":"2026-04-23T20:33:29.983597+08:00","gmt_modified":"2026-04-23T20:33:29.983597+08:00"},{"id":"72f6d334026866e8a61d2ffb1d83370a","path":"backend/app/workers/citation_engine.py","line_range":"19-100","gmt_create":"2026-04-23T20:33:29.986927+08:00","gmt_modified":"2026-04-23T20:33:29.986928+08:00"},{"id":"1d84b9a7eb013882953a2d1d948299e4","path":"backend/app/workers/platforms/kimi.py","line_range":"126-197","gmt_create":"2026-04-23T20:33:29.990308+08:00","gmt_modified":"2026-04-23T20:33:29.990308+08:00"},{"id":"ba687f2c64aff92b3906658359ed953a","path":"backend/app/workers/platforms/wenxin.py","line_range":"124-195","gmt_create":"2026-04-23T20:33:29.991213+08:00","gmt_modified":"2026-04-23T20:33:29.991213+08:00"},{"id":"52ee729b02c992c689522c7956c14128","path":"backend/app/workers/scheduler.py","line_range":"57-62","gmt_create":"2026-04-23T20:33:29.992799+08:00","gmt_modified":"2026-04-23T20:33:29.992799+08:00"},{"id":"c9e32b7324cce60c8887deb8404ee759","path":"backend/app/workers/scheduler.py","line_range":"107-112","gmt_create":"2026-04-23T20:33:29.99333+08:00","gmt_modified":"2026-04-23T20:33:29.99333+08:00"},{"id":"8355d3821337334caee57a75dc8c8865","path":"backend/app/services/query.py","line_range":"116-130","gmt_create":"2026-04-23T20:33:29.994505+08:00","gmt_modified":"2026-04-23T20:33:29.994505+08:00"},{"id":"4fe27d4d1323b500e72d870aa6212a1a","path":"backend/app/workers/scheduler.py","line_range":"13-20","gmt_create":"2026-04-23T20:33:29.996199+08:00","gmt_modified":"2026-04-23T20:33:29.996199+08:00"},{"id":"3729543092bccad8926c5ea852db1e69","path":"backend/app/workers/citation_engine.py","line_range":"148-157","gmt_create":"2026-04-23T20:33:29.996517+08:00","gmt_modified":"2026-04-23T20:33:29.996517+08:00"},{"id":"1ee5153c867fc6e9d277a3067963a1fc","path":"backend/app/workers/scheduler.py","line_range":"32-38","gmt_create":"2026-04-23T20:33:29.997154+08:00","gmt_modified":"2026-04-23T20:33:29.997154+08:00"},{"id":"ed527c7a549ec333c2b30b59614343df","path":"backend/app/models/query.py","line_range":"50-54","gmt_create":"2026-04-23T20:33:29.997453+08:00","gmt_modified":"2026-04-23T20:33:29.997453+08:00"},{"id":"1a3351698ecc7cd4e508b7a792804fc4","path":"backend/app/workers/citation_engine.py","line_range":"302-309","gmt_create":"2026-04-23T20:33:29.999284+08:00","gmt_modified":"2026-04-23T20:33:29.999284+08:00"},{"id":"e3e9710c7eead933c936519395f792e0","path":"backend/app/workers/scheduler.py","line_range":"44-49","gmt_create":"2026-04-23T20:33:30.00043+08:00","gmt_modified":"2026-04-23T20:33:30.000431+08:00"},{"id":"a4143cc29b14f1f5bc75a5e021690666","path":"backend/app/workers/platforms/kimi.py","line_range":"23-31","gmt_create":"2026-04-23T20:33:30.001466+08:00","gmt_modified":"2026-04-23T20:33:30.001466+08:00"},{"id":"7192cfda5508e7587efd91d26cf1f018","path":"backend/app/workers/platforms/wenxin.py","line_range":"23-31","gmt_create":"2026-04-23T20:33:30.002099+08:00","gmt_modified":"2026-04-23T20:33:30.002099+08:00"},{"id":"38142b7d7016c5590e638fafcdcb1a19","path":"backend/app/workers/citation_engine.py","line_range":"211-227","gmt_create":"2026-04-23T20:33:30.002775+08:00","gmt_modified":"2026-04-23T20:33:30.002775+08:00"},{"id":"fb5276346dcc4e7044d8765a8572e7a8","path":"backend/app/config.py","line_range":"4-16","gmt_create":"2026-04-23T20:33:30.003374+08:00","gmt_modified":"2026-04-23T20:33:30.003377+08:00"},{"id":"482d573f97b482b99bcde1c399eceb73","path":"backend/app/api/queries.py","line_range":"90-108","gmt_create":"2026-04-23T20:33:37.21132+08:00","gmt_modified":"2026-04-23T20:33:37.21132+08:00"},{"id":"56f44cc97867cee3e5663424134d6072","path":"backend/app/workers/platforms/kimi.py","line_range":"1-37","gmt_create":"2026-04-23T20:33:37.212923+08:00","gmt_modified":"2026-04-23T20:33:37.212923+08:00"},{"id":"2e326ef8322619f1e8b3873022cb0437","path":"backend/app/workers/platforms/wenxin.py","line_range":"1-37","gmt_create":"2026-04-23T20:33:37.213348+08:00","gmt_modified":"2026-04-23T20:33:37.213348+08:00"},{"id":"4cac57dbc530f0335c913ec5725dfa4f","path":"backend/app/workers/scheduler.py","line_range":"1-121","gmt_create":"2026-04-23T20:33:37.215373+08:00","gmt_modified":"2026-04-23T20:33:37.215373+08:00"},{"id":"db174cfe219fc84d0dd26529f047b1d0","path":"backend/app/workers/citation_engine.py","line_range":"161-330","gmt_create":"2026-04-23T20:33:37.22028+08:00","gmt_modified":"2026-04-23T20:33:37.22028+08:00"},{"id":"f36452f78aabfb0c46da03bbe25dff06","path":"backend/app/services/citation.py","line_range":"219-295","gmt_create":"2026-04-23T20:33:37.223165+08:00","gmt_modified":"2026-04-23T20:33:37.223165+08:00"},{"id":"52c01d7b9c17aa16944cbfcf8885be61","path":"backend/app/workers/platforms/kimi.py","line_range":"16-33","gmt_create":"2026-04-23T20:33:37.227954+08:00","gmt_modified":"2026-04-23T20:33:37.227954+08:00"},{"id":"9d352899554ab41b65b2e9f32558d811","path":"backend/app/workers/citation_engine.py","line_range":"39-113","gmt_create":"2026-04-23T20:33:37.229053+08:00","gmt_modified":"2026-04-23T20:33:37.229053+08:00"},{"id":"b1ee5a992230844ba898765be63f7b27","path":"backend/app/workers/citation_engine.py","line_range":"32-133","gmt_create":"2026-04-23T20:33:37.229555+08:00","gmt_modified":"2026-04-23T20:33:37.229555+08:00"},{"id":"cb098a3cd32339e99f755dfd0fc35b5c","path":"tests/test_citation_engine.py","line_range":"6-127","gmt_create":"2026-04-23T20:33:37.230048+08:00","gmt_modified":"2026-04-23T20:33:37.230049+08:00"},{"id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","path":"backend/app/workers/citation_engine.py","line_range":"145-158","gmt_create":"2026-04-23T20:33:37.230491+08:00","gmt_modified":"2026-04-23T20:33:37.230491+08:00"},{"id":"4e9b3d0e94282f4bc6fa500f4eed61a1","path":"backend/app/workers/citation_engine.py","line_range":"135-159","gmt_create":"2026-04-23T20:33:37.231003+08:00","gmt_modified":"2026-04-23T20:33:37.231003+08:00"},{"id":"8e3201561a9dd9a06ee3bf68ffdb3f99","path":"tests/test_citation_engine.py","line_range":"39-109","gmt_create":"2026-04-23T20:33:37.231501+08:00","gmt_modified":"2026-04-23T20:33:37.231501+08:00"},{"id":"c3a417be3d61f5bcd3fbf976e0c4f15a","path":"backend/app/workers/scheduler.py","line_range":"33-121","gmt_create":"2026-04-23T20:33:37.238099+08:00","gmt_modified":"2026-04-23T20:33:37.238099+08:00"},{"id":"7ce954ed7d3bc4dcf78630124cc0dd88","path":"backend/app/services/citation.py","line_range":"264-295","gmt_create":"2026-04-23T20:33:37.244499+08:00","gmt_modified":"2026-04-23T20:33:37.244499+08:00"},{"id":"7289a3568c137c8a671fc8c963bb8d28","path":"backend/requirements.txt","line_range":"1-35","gmt_create":"2026-04-23T20:33:37.24795+08:00","gmt_modified":"2026-04-23T20:33:37.24795+08:00"},{"id":"ef82ce4377c549013c200e19701a6805","path":"backend/app/workers/platforms/kimi.py","line_range":"21-32","gmt_create":"2026-04-23T20:33:37.254004+08:00","gmt_modified":"2026-04-23T20:33:37.254004+08:00"},{"id":"c7986eb1be0ffdd9ec4e243be4270119","path":"backend/app/workers/platforms/wenxin.py","line_range":"21-32","gmt_create":"2026-04-23T20:33:37.254558+08:00","gmt_modified":"2026-04-23T20:33:37.254558+08:00"},{"id":"5563b3bd56550648dc70302c1762ce5a","path":"backend/app/workers/platforms/tongyi.py","line_range":"18-29","gmt_create":"2026-04-23T20:33:37.255643+08:00","gmt_modified":"2026-04-23T20:33:37.255643+08:00"},{"id":"91852ef8dcc844a2f85e9fce0227ab74","path":"backend/app/workers/platforms/doubao.py","line_range":"18-29","gmt_create":"2026-04-23T20:33:37.25603+08:00","gmt_modified":"2026-04-23T20:33:37.25603+08:00"},{"id":"1b46fab9e22f53db30ead5677d03e3e2","path":"backend/app/workers/citation_engine.py","line_range":"11-16","gmt_create":"2026-04-23T20:33:37.256413+08:00","gmt_modified":"2026-04-23T20:33:37.256413+08:00"},{"id":"4a2fa09aa3a948dec5ef8ba873b0e716","path":"backend/app/services/citation.py","line_range":"14-42","gmt_create":"2026-04-23T20:33:37.257057+08:00","gmt_modified":"2026-04-23T20:33:37.257057+08:00"},{"id":"e7afbab5932c93c3469f1a225e6c7156","path":"backend/app/api/citations.py","line_range":"1-55","gmt_create":"2026-04-23T20:33:57.479092+08:00","gmt_modified":"2026-04-23T20:33:57.479092+08:00"},{"id":"a0eac56d622a2fff529bc2b796064bcd","path":"backend/app/schemas/query.py","line_range":"1-94","gmt_create":"2026-04-23T20:33:57.479659+08:00","gmt_modified":"2026-04-23T20:33:57.479659+08:00"},{"id":"174be58163b6f72b4cd4a493f3463ce4","path":"backend/app/schemas/citation.py","line_range":"1-52","gmt_create":"2026-04-23T20:33:57.480222+08:00","gmt_modified":"2026-04-23T20:33:57.480222+08:00"},{"id":"136f172c732d0cc130532a4f0df475a4","path":"backend/app/models/user.py","line_range":"1-41","gmt_create":"2026-04-23T20:33:57.481714+08:00","gmt_modified":"2026-04-23T20:33:57.481714+08:00"},{"id":"916551131bd9ac8c9f9c8bb762af1fa4","path":"backend/app/services/query.py","line_range":"1-130","gmt_create":"2026-04-23T20:33:57.482172+08:00","gmt_modified":"2026-04-23T20:33:57.482172+08:00"},{"id":"5d2836286eb7d4eb6039b004a9744d26","path":"backend/app/services/citation.py","line_range":"1-429","gmt_create":"2026-04-23T20:33:57.482643+08:00","gmt_modified":"2026-04-23T20:33:57.482643+08:00"},{"id":"39a3b2d9301fa4eff7bef0fda3352790","path":"backend/app/workers/platforms/kimi.py","line_range":"1-206","gmt_create":"2026-04-23T20:33:57.484464+08:00","gmt_modified":"2026-04-23T20:33:57.484464+08:00"},{"id":"fbcfae3b1238b3da5329ebafe4294861","path":"backend/app/workers/platforms/wenxin.py","line_range":"1-205","gmt_create":"2026-04-23T20:33:57.484977+08:00","gmt_modified":"2026-04-23T20:33:57.484977+08:00"},{"id":"c4273407c88f470df7daf6a8ad5ce969","path":"backend/app/api/queries.py","line_range":"15-109","gmt_create":"2026-04-23T20:33:57.485748+08:00","gmt_modified":"2026-04-23T20:33:57.485748+08:00"},{"id":"35774e0a09ac5459c868914d7182ca95","path":"backend/app/api/citations.py","line_range":"19-55","gmt_create":"2026-04-23T20:33:57.486195+08:00","gmt_modified":"2026-04-23T20:33:57.486195+08:00"},{"id":"f639b566c26dfd18b24e3dfd2e9853ac","path":"backend/app/schemas/citation.py","line_range":"7-52","gmt_create":"2026-04-23T20:33:57.486916+08:00","gmt_modified":"2026-04-23T20:33:57.486916+08:00"},{"id":"b46654006178160f12897e2c5baac8fa","path":"backend/app/services/citation.py","line_range":"219-429","gmt_create":"2026-04-23T20:33:57.488934+08:00","gmt_modified":"2026-04-23T20:33:57.488934+08:00"},{"id":"82265d393c20d0af96beec6b9c657c27","path":"backend/app/api/queries.py","line_range":"28-41","gmt_create":"2026-04-23T20:33:57.49175+08:00","gmt_modified":"2026-04-23T20:33:57.49175+08:00"},{"id":"93e5c95b1691bb81a36bf9a0ac889030","path":"backend/app/services/citation.py","line_range":"219-261","gmt_create":"2026-04-23T20:33:57.493276+08:00","gmt_modified":"2026-04-23T20:33:57.493276+08:00"},{"id":"374200f0bf946f0399351756977d0495","path":"backend/app/workers/citation_engine.py","line_range":"176-234","gmt_create":"2026-04-23T20:33:57.498134+08:00","gmt_modified":"2026-04-23T20:33:57.498134+08:00"},{"id":"9a8d9100a6bc34ebae9ee065def7e88a","path":"backend/app/schemas/query.py","line_range":"44-72","gmt_create":"2026-04-23T20:33:57.500036+08:00","gmt_modified":"2026-04-23T20:33:57.500036+08:00"},{"id":"93c23bcc3456826af17e26a6d4c32116","path":"backend/app/schemas/query.py","line_range":"6-9","gmt_create":"2026-04-23T20:33:57.500633+08:00","gmt_modified":"2026-04-23T20:33:57.500633+08:00"},{"id":"c17eeb8726297096cd5542283f11494f","path":"backend/app/api/queries.py","line_range":"17-109","gmt_create":"2026-04-23T20:33:57.5019+08:00","gmt_modified":"2026-04-23T20:33:57.5019+08:00"},{"id":"08fec4718be6991260c00ca532f9173a","path":"backend/app/api/citations.py","line_range":"22-55","gmt_create":"2026-04-23T20:33:57.502347+08:00","gmt_modified":"2026-04-23T20:33:57.502347+08:00"},{"id":"08007199eea846dd14f15f7dc70419e2","path":"backend/app/schemas/citation.py","line_range":"48-52","gmt_create":"2026-04-23T20:33:57.50265+08:00","gmt_modified":"2026-04-23T20:33:57.50265+08:00"},{"id":"4caff756fd4da029bd64cd16e7ef5960","path":"backend/app/api/queries.py","line_range":"32-39","gmt_create":"2026-04-23T20:33:57.50293+08:00","gmt_modified":"2026-04-23T20:33:57.50293+08:00"},{"id":"b0220895f66f1273966ad5b2c3266952","path":"backend/app/api/queries.py","line_range":"49-53","gmt_create":"2026-04-23T20:33:57.503622+08:00","gmt_modified":"2026-04-23T20:33:57.503622+08:00"},{"id":"44f88f9664fdf6e84ffb7e0675a86a28","path":"backend/app/api/queries.py","line_range":"64-69","gmt_create":"2026-04-23T20:33:57.504188+08:00","gmt_modified":"2026-04-23T20:33:57.504188+08:00"},{"id":"91f280f51389bd1cf711dcf33a4da681","path":"backend/app/api/queries.py","line_range":"79-84","gmt_create":"2026-04-23T20:33:57.504712+08:00","gmt_modified":"2026-04-23T20:33:57.504712+08:00"},{"id":"ab50466a57c77659d7b469d3a8a04ddb","path":"backend/app/api/queries.py","line_range":"96-103","gmt_create":"2026-04-23T20:33:57.505025+08:00","gmt_modified":"2026-04-23T20:33:57.505025+08:00"},{"id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","path":"backend/app/api/citations.py","line_range":"65-71","gmt_create":"2026-04-23T20:33:57.505311+08:00","gmt_modified":"2026-04-23T20:33:57.505311+08:00"},{"id":"82386bc7ca57d9ccc94b656e52bc89f6","path":"backend/app/api/queries.py","line_range":"1-14","gmt_create":"2026-04-23T20:33:57.506573+08:00","gmt_modified":"2026-04-23T20:33:57.506573+08:00"},{"id":"7ab79ab21d7d6e4dbcb224572516f6f6","path":"backend/app/api/citations.py","line_range":"1-19","gmt_create":"2026-04-23T20:33:57.507421+08:00","gmt_modified":"2026-04-23T20:33:57.507422+08:00"},{"id":"8433204d7a82a1f480e57df9ceee5581","path":"backend/app/services/query.py","line_range":"1-10","gmt_create":"2026-04-23T20:33:57.507906+08:00","gmt_modified":"2026-04-23T20:33:57.507906+08:00"},{"id":"3957ee6f15a01b7b541490438ef18684","path":"backend/app/services/citation.py","line_range":"1-17","gmt_create":"2026-04-23T20:33:57.508376+08:00","gmt_modified":"2026-04-23T20:33:57.508376+08:00"},{"id":"fcae8d1d281ad7186999cc4ca8e43db7","path":"backend/app/workers/scheduler.py","line_range":"25-39","gmt_create":"2026-04-23T20:33:57.509666+08:00","gmt_modified":"2026-04-23T20:33:57.509666+08:00"},{"id":"ee12a84ac6334b13e20132181454488b","path":"backend/app/workers/scheduler.py","line_range":"13-19","gmt_create":"2026-04-23T20:33:57.510112+08:00","gmt_modified":"2026-04-23T20:33:57.510112+08:00"},{"id":"897e047b94772e5a0ff57cf773a7f965","path":"backend/app/workers/platforms/kimi.py","line_range":"17-32","gmt_create":"2026-04-23T20:33:57.510534+08:00","gmt_modified":"2026-04-23T20:33:57.510534+08:00"},{"id":"53e8ec81b4d2dbb13c831048e5897036","path":"backend/app/workers/platforms/wenxin.py","line_range":"17-32","gmt_create":"2026-04-23T20:33:57.510845+08:00","gmt_modified":"2026-04-23T20:33:57.510845+08:00"},{"id":"fd3145047b9c813cc8e64b9322e531f9","path":"backend/app/services/citation.py","line_range":"219-327","gmt_create":"2026-04-23T20:33:57.516693+08:00","gmt_modified":"2026-04-23T20:33:57.516693+08:00"},{"id":"b09a0f415030d91b25e6cabd8a0a93fc","path":"backend/app/models/query_task.py","line_range":"176-289","gmt_create":"2026-04-23T20:33:57.51758+08:00","gmt_modified":"2026-04-23T20:33:57.51758+08:00"},{"id":"e2168959b26c386940370b5f1bf48d7d","path":"backend/app/models/citation_record.py","line_range":"194-204","gmt_create":"2026-04-23T20:33:57.517939+08:00","gmt_modified":"2026-04-23T20:33:57.517939+08:00"},{"id":"129573d2bbcde48697ed0e75dea12396","path":"backend/app/workers/scheduler.py","line_range":"25-40","gmt_create":"2026-04-23T20:35:18.586153+08:00","gmt_modified":"2026-04-23T20:35:18.586153+08:00"},{"id":"cf18c97a9be6c78aa43cc229ed3dad20","path":"backend/app/workers/citation_engine.py","line_range":"164-173","gmt_create":"2026-04-23T20:35:18.586656+08:00","gmt_modified":"2026-04-23T20:35:18.586656+08:00"},{"id":"3c7ca5d582dca31c2530b1ce9c058e95","path":"backend/app/workers/platforms/kimi.py","line_range":"10-37","gmt_create":"2026-04-23T20:35:18.587239+08:00","gmt_modified":"2026-04-23T20:35:18.587239+08:00"},{"id":"27047f868643e5457d4f242b4298a9f6","path":"frontend/lib/platforms.ts","line_range":"1-23","gmt_create":"2026-04-23T20:35:18.590782+08:00","gmt_modified":"2026-04-23T20:35:18.590782+08:00"},{"id":"1526e4e02133a48eac04befb74ec5bd1","path":"backend/app/workers/citation_engine.py","line_range":"161-173","gmt_create":"2026-04-23T20:35:18.592183+08:00","gmt_modified":"2026-04-23T20:35:18.592183+08:00"},{"id":"98c02d9bb7aa6e2b6be5f7381e64fd99","path":"backend/app/api/queries.py","line_range":"26-39","gmt_create":"2026-04-23T20:35:18.594026+08:00","gmt_modified":"2026-04-23T20:35:18.594026+08:00"},{"id":"2a971cb83924013902324eceeab22559","path":"backend/app/workers/platforms/kimi.py","line_range":"16-29","gmt_create":"2026-04-23T20:35:18.596805+08:00","gmt_modified":"2026-04-23T20:35:18.596805+08:00"},{"id":"99326fedad9275392719105b5b6782d6","path":"backend/app/workers/platforms/kimi.py","line_range":"31-33","gmt_create":"2026-04-23T20:35:18.597389+08:00","gmt_modified":"2026-04-23T20:35:18.597389+08:00"},{"id":"5e5dacc623918c0f1eba234154c99291","path":"backend/app/workers/platforms/search_engine.py","line_range":"16-76","gmt_create":"2026-04-23T20:35:18.598978+08:00","gmt_modified":"2026-04-23T20:35:18.598978+08:00"},{"id":"5be7e6cf82d6359efddaf131aaf92615","path":"backend/app/workers/citation_engine.py","line_range":"323-330","gmt_create":"2026-04-23T20:35:18.604342+08:00","gmt_modified":"2026-04-23T20:35:18.604342+08:00"},{"id":"129b746e71a9013ceb1b0fcc59942b39","path":"backend/app/workers/scheduler.py","line_range":"86-90","gmt_create":"2026-04-23T20:35:18.611167+08:00","gmt_modified":"2026-04-23T20:35:18.611167+08:00"},{"id":"d780e807ee751f39f331a658b47c4ed3","path":"backend/app/services/citation.py","line_range":"24-269","gmt_create":"2026-04-23T20:35:18.619146+08:00","gmt_modified":"2026-04-23T20:35:18.619146+08:00"},{"id":"8eea43550951387ac740b5e3e64c7691","path":"backend/app/workers/platforms/search_engine.py","line_range":"94-96","gmt_create":"2026-04-23T20:35:18.629044+08:00","gmt_modified":"2026-04-23T20:35:18.629044+08:00"},{"id":"37769b7e6b5588be0065681dedf514ed","path":"backend/app/workers/platforms/search_engine.py","line_range":"140-144","gmt_create":"2026-04-23T20:35:18.631486+08:00","gmt_modified":"2026-04-23T20:35:18.631486+08:00"},{"id":"518d184988b97ebc7ef0c0bf5c10f42c","path":"backend/app/workers/platforms/kimi.py","line_range":"24-29","gmt_create":"2026-04-23T20:35:18.631835+08:00","gmt_modified":"2026-04-23T20:35:18.631835+08:00"},{"id":"818504ee2e17d2f9cc8fe115ca321138","path":"backend/app/api/queries.py","line_range":"34-38","gmt_create":"2026-04-23T20:35:18.632132+08:00","gmt_modified":"2026-04-23T20:35:18.632132+08:00"},{"id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","path":"backend/app/api/citations.py","line_range":"25-56","gmt_create":"2026-04-23T20:35:18.633686+08:00","gmt_modified":"2026-04-23T20:35:18.633686+08:00"},{"id":"86e37040be1aeb400fab9b529f5404c8","path":"backend/app/models/subscription.py","line_range":"1-37","gmt_create":"2026-04-23T20:35:45.583254+08:00","gmt_modified":"2026-04-23T20:35:45.583254+08:00"},{"id":"211463f5b49610f09594c40c0a235943","path":"backend/alembic/env.py","line_range":"1-89","gmt_create":"2026-04-23T20:35:45.584058+08:00","gmt_modified":"2026-04-23T20:35:45.584058+08:00"},{"id":"48d22eaee09e364a293ad6c4750f5c5a","path":"docker-compose.yml","line_range":"1-71","gmt_create":"2026-04-23T20:35:45.587653+08:00","gmt_modified":"2026-04-23T20:35:45.587653+08:00"},{"id":"98cc82f62b83678f06a33cf9231ecdf8","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"1-128","gmt_create":"2026-04-23T20:35:45.597037+08:00","gmt_modified":"2026-04-23T20:35:45.597037+08:00"},{"id":"e1aabd52989e47806fb997157381e1cf","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","line_range":"1-37","gmt_create":"2026-04-23T20:35:45.597747+08:00","gmt_modified":"2026-04-23T20:35:45.597747+08:00"},{"id":"ac77e4875817616194b7b5997d4fb1ae","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"57-94","gmt_create":"2026-04-23T20:35:45.611901+08:00","gmt_modified":"2026-04-23T20:35:45.611901+08:00"},{"id":"0e57efd98dacc85da21f995980371ee4","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","line_range":"21-37","gmt_create":"2026-04-23T20:35:45.61338+08:00","gmt_modified":"2026-04-23T20:35:45.61338+08:00"},{"id":"d34337b9ff77246979252d2fd8fb8018","path":"backend/alembic/env.py","line_range":"33-88","gmt_create":"2026-04-23T20:35:45.628352+08:00","gmt_modified":"2026-04-23T20:35:45.628353+08:00"},{"id":"eb63042f04a22f9a67bd498df1684d20","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","line_range":"36-111","gmt_create":"2026-04-23T20:35:45.634829+08:00","gmt_modified":"2026-04-23T20:35:45.634829+08:00"},{"id":"c651c7ad6747a92ee96eabb2eb82afdd","path":"backend/app/database.py","line_range":"12-18","gmt_create":"2026-04-23T20:35:45.637195+08:00","gmt_modified":"2026-04-23T20:35:45.637195+08:00"},{"id":"dd01eee487298a28e950f6345196f1d4","path":"backend/app/services/citation.py","line_range":"30-79","gmt_create":"2026-04-23T20:35:45.637815+08:00","gmt_modified":"2026-04-23T20:35:45.637815+08:00"},{"id":"7dae7237f11c5100bf7889c105193cf6","path":"backend/app/services/query.py","line_range":"12-32","gmt_create":"2026-04-23T20:35:45.638422+08:00","gmt_modified":"2026-04-23T20:35:45.638422+08:00"},{"id":"cc64cf609f5ff218f618e0664ffa7cc7","path":"backend/app/services/citation.py","line_range":"298-308","gmt_create":"2026-04-23T20:35:45.641905+08:00","gmt_modified":"2026-04-23T20:35:45.641905+08:00"},{"id":"ce7e334595a4ce912e0d116314db9a35","path":"backend/app/services/citation.py","line_range":"342-429","gmt_create":"2026-04-23T20:35:45.6442+08:00","gmt_modified":"2026-04-23T20:35:45.6442+08:00"},{"id":"2f46f212597e3c245b9e5dcc5dbc863d","path":"backend/app/schemas/citation.py","line_range":"7-18","gmt_create":"2026-04-23T20:35:45.64501+08:00","gmt_modified":"2026-04-23T20:35:45.64501+08:00"},{"id":"dc40f1dd3e59ee7f046019201068bea1","path":"backend/app/services/citation.py","line_range":"14-22","gmt_create":"2026-04-23T20:35:45.659571+08:00","gmt_modified":"2026-04-23T20:35:45.659571+08:00"},{"id":"01a0c4b40819965823b56e9da858c024","path":"frontend/Dockerfile","line_range":"1-15","gmt_create":"2026-04-23T21:00:59.634151+08:00","gmt_modified":"2026-04-23T21:00:59.634151+08:00"},{"id":"13f6ca76349ef86ae756bb519f122bc5","path":"backend/alembic.ini","line_range":"1-150","gmt_create":"2026-04-23T21:00:59.636129+08:00","gmt_modified":"2026-04-23T21:00:59.636129+08:00"},{"id":"74abd6612105c29b67178fa9dbd04b61","path":"frontend/tsconfig.json","line_range":"1-27","gmt_create":"2026-04-23T21:00:59.639808+08:00","gmt_modified":"2026-04-23T21:00:59.639808+08:00"},{"id":"9482f4f6279a4f636b77e69b8273b996","path":"backend/alembic.ini","line_range":"86-114","gmt_create":"2026-04-23T21:00:59.64068+08:00","gmt_modified":"2026-04-23T21:00:59.64068+08:00"},{"id":"397b266f19a1addebdf6c32db71ae77f","path":"tests/conftest.py","line_range":"1-71","gmt_create":"2026-04-23T21:00:59.640958+08:00","gmt_modified":"2026-04-23T21:00:59.640958+08:00"},{"id":"eb603ec2611957de67af00756f4b1efa","path":"backend/app/config.py","line_range":"7-13","gmt_create":"2026-04-23T21:00:59.64236+08:00","gmt_modified":"2026-04-23T21:00:59.64236+08:00"},{"id":"c25b39830f3b7734da975acc7f214666","path":"backend/Dockerfile","line_range":"31-33","gmt_create":"2026-04-23T21:00:59.642682+08:00","gmt_modified":"2026-04-23T21:00:59.642682+08:00"},{"id":"4c9d362ecce8e796e6f14850def049b0","path":"docker-compose.yml","line_range":"4-20","gmt_create":"2026-04-23T21:00:59.642976+08:00","gmt_modified":"2026-04-23T21:00:59.642976+08:00"},{"id":"d5827be2cfbe41c8177660ae877e93a4","path":"docker-compose.yml","line_range":"22-34","gmt_create":"2026-04-23T21:00:59.643262+08:00","gmt_modified":"2026-04-23T21:00:59.643262+08:00"},{"id":"03a65cdcfc173217d12ad8a417f8f033","path":"backend/app/main.py","line_range":"13-21","gmt_create":"2026-04-23T21:00:59.643535+08:00","gmt_modified":"2026-04-23T21:00:59.643535+08:00"},{"id":"3365fa8db33d43bab1d0a614e8af3a70","path":"backend/app/main.py","line_range":"45-47","gmt_create":"2026-04-23T21:00:59.644124+08:00","gmt_modified":"2026-04-23T21:00:59.644124+08:00"},{"id":"6f637c2b0796ec533aafb3b865c11cf0","path":"backend/app/schemas/auth.py","line_range":"1-34","gmt_create":"2026-04-23T21:00:59.646408+08:00","gmt_modified":"2026-04-23T21:00:59.646408+08:00"},{"id":"37bbab6e4f16db7eac6eee9d05e80e46","path":"README.md","line_range":"1-3","gmt_create":"2026-04-23T21:00:59.649625+08:00","gmt_modified":"2026-04-23T21:00:59.649625+08:00"},{"id":"bf363deac5ef38c8dc80c73b862e730b","path":"docker-compose.yml","line_range":"4-34","gmt_create":"2026-04-23T21:00:59.651828+08:00","gmt_modified":"2026-04-23T21:00:59.651828+08:00"},{"id":"c6e94075e5f689bfa2fe16f8cf965203","path":"tests/conftest.py","line_range":"19-50","gmt_create":"2026-04-23T21:00:59.65241+08:00","gmt_modified":"2026-04-23T21:00:59.65241+08:00"},{"id":"1a78f5574add6d07a1d7c947dba3f23d","path":"backend/alembic.ini","line_range":"115-150","gmt_create":"2026-04-23T21:00:59.652679+08:00","gmt_modified":"2026-04-23T21:00:59.652679+08:00"},{"id":"f6810849c947471a4b45d7ca01ec8c5f","path":"frontend/tailwind.config.ts","line_range":"5-9","gmt_create":"2026-04-23T21:00:59.653659+08:00","gmt_modified":"2026-04-23T21:00:59.653659+08:00"},{"id":"9f6d9941f3b93e29d714bfec7e83434c","path":"backend/app/main.py","line_range":"30-36","gmt_create":"2026-04-23T21:00:59.653983+08:00","gmt_modified":"2026-04-23T21:00:59.653984+08:00"},{"id":"85792f0b1e34b5b48b0300aa606ed6e6","path":"backend/app/main.py","line_range":"1-56","gmt_create":"2026-04-23T21:02:44.159246+08:00","gmt_modified":"2026-04-23T21:02:44.159246+08:00"},{"id":"f240c1067c223a019ba05b0fbd718aa4","path":"backend/app/main.py","line_range":"1-84","gmt_create":"2026-04-24T10:58:35.335284+08:00","gmt_modified":"2026-04-24T10:58:35.335284+08:00"},{"id":"a9fb75d1fdb833a11b36bc7b298f19be","path":"frontend/lib/api.ts","line_range":"1-154","gmt_create":"2026-04-24T10:58:35.349742+08:00","gmt_modified":"2026-04-24T10:58:35.349742+08:00"},{"id":"40325db1cb621a9af027150a8c5cf8e9","path":"frontend/lib/auth.ts","line_range":"1-73","gmt_create":"2026-04-24T10:58:35.350062+08:00","gmt_modified":"2026-04-24T10:58:35.350062+08:00"},{"id":"93d8c6a312849c344b6a9713b671840f","path":"backend/requirements.txt","line_range":"1-39","gmt_create":"2026-04-24T10:58:35.35098+08:00","gmt_modified":"2026-04-24T10:58:35.35098+08:00"},{"id":"844b21a35ae39ead76ff8831eb974e5a","path":"backend/app/main.py","line_range":"81-84","gmt_create":"2026-04-24T10:58:35.352287+08:00","gmt_modified":"2026-04-24T10:58:35.352287+08:00"},{"id":"3af33bd686ce3d418e31843cac66f58b","path":"backend/README.md","line_range":"12-67","gmt_create":"2026-04-24T10:58:35.35614+08:00","gmt_modified":"2026-04-24T10:58:35.356141+08:00"},{"id":"06c6dfcd66159d42fa9b9eafd1e36a04","path":"frontend/README.md","line_range":"11-34","gmt_create":"2026-04-24T10:58:35.35673+08:00","gmt_modified":"2026-04-24T10:58:35.35673+08:00"},{"id":"903da86dc3fb26783f45f247d60e9534","path":"backend/README.md","line_range":"69-126","gmt_create":"2026-04-24T10:58:35.357072+08:00","gmt_modified":"2026-04-24T10:58:35.357072+08:00"},{"id":"0ffe337a73c8fb7254f3e48932a8ae7f","path":"backend/README.md","line_range":"209-234","gmt_create":"2026-04-24T10:58:35.357641+08:00","gmt_modified":"2026-04-24T10:58:35.357642+08:00"},{"id":"55369db351eb916a3210b22f3d672162","path":"frontend/README.md","line_range":"161-170","gmt_create":"2026-04-24T10:58:35.358984+08:00","gmt_modified":"2026-04-24T10:58:35.358984+08:00"},{"id":"6c080aba7d0e611bd4e7f268835b630f","path":"backend/app/middleware/logging_middleware.py","line_range":"1-24","gmt_create":"2026-04-24T10:58:51.060864+08:00","gmt_modified":"2026-04-24T10:58:51.060864+08:00"},{"id":"a7bba55ddc4dd5d215e881e8432d83ea","path":"backend/app/middleware/rate_limit.py","line_range":"1-83","gmt_create":"2026-04-24T10:58:51.061198+08:00","gmt_modified":"2026-04-24T10:58:51.061198+08:00"},{"id":"7c7425c51cc43b8840cefd9764b47204","path":"backend/app/api/admin.py","line_range":"1-108","gmt_create":"2026-04-24T10:58:51.061492+08:00","gmt_modified":"2026-04-24T10:58:51.061492+08:00"},{"id":"6e4a52820e780e4b42651a8214ad4493","path":"backend/app/api/reports.py","line_range":"1-75","gmt_create":"2026-04-24T10:58:51.061762+08:00","gmt_modified":"2026-04-24T10:58:51.061763+08:00"},{"id":"4247da3fc00a7e5f8b73775321eccf8e","path":"backend/app/api/subscriptions.py","line_range":"1-77","gmt_create":"2026-04-24T10:58:51.062039+08:00","gmt_modified":"2026-04-24T10:58:51.062039+08:00"},{"id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","path":"backend/app/services/admin.py","line_range":"1-188","gmt_create":"2026-04-24T10:58:51.062452+08:00","gmt_modified":"2026-04-24T10:58:51.062452+08:00"},{"id":"557281ca025f76d0dc2db67e56b44053","path":"backend/app/services/subscription.py","line_range":"1-155","gmt_create":"2026-04-24T10:58:51.062795+08:00","gmt_modified":"2026-04-24T10:58:51.062795+08:00"},{"id":"e2d4838e58acc0eee236ef586abab64e","path":"backend/app/main.py","line_range":"13-48","gmt_create":"2026-04-24T10:58:51.064016+08:00","gmt_modified":"2026-04-24T10:58:51.064016+08:00"},{"id":"8aee7654d1f435ab53d8ddaabd269fed","path":"backend/app/database.py","line_range":"6-29","gmt_create":"2026-04-24T10:58:51.06434+08:00","gmt_modified":"2026-04-24T10:58:51.06434+08:00"},{"id":"acd9e6c32084e589d5aeb1665d918dfd","path":"backend/app/api/deps.py","line_range":"13-43","gmt_create":"2026-04-24T10:58:51.064666+08:00","gmt_modified":"2026-04-24T10:58:51.064667+08:00"},{"id":"33ec8bca51cb9f667bf91088dd6b6a70","path":"backend/app/main.py","line_range":"24-48","gmt_create":"2026-04-24T10:58:51.065096+08:00","gmt_modified":"2026-04-24T10:58:51.065096+08:00"},{"id":"712424bd3bd3d5f39b1a0a72acc9952a","path":"backend/app/middleware/rate_limit.py","line_range":"10-83","gmt_create":"2026-04-24T10:58:51.065564+08:00","gmt_modified":"2026-04-24T10:58:51.065564+08:00"},{"id":"9357a0fcca02068d428f4a191d08fdcd","path":"backend/app/middleware/logging_middleware.py","line_range":"8-24","gmt_create":"2026-04-24T10:58:51.065888+08:00","gmt_modified":"2026-04-24T10:58:51.065888+08:00"},{"id":"8efcce12915471fe5b88fe058bcf238e","path":"backend/app/services/auth.py","line_range":"16-69","gmt_create":"2026-04-24T10:58:51.06648+08:00","gmt_modified":"2026-04-24T10:58:51.06648+08:00"},{"id":"7f81ebbdde3496054e6f43f5eef366dc","path":"backend/app/services/admin.py","line_range":"14-188","gmt_create":"2026-04-24T10:58:51.06683+08:00","gmt_modified":"2026-04-24T10:58:51.06683+08:00"},{"id":"f4d57f9a78585969a006b7451ea8ce84","path":"backend/app/services/subscription.py","line_range":"69-155","gmt_create":"2026-04-24T10:58:51.06716+08:00","gmt_modified":"2026-04-24T10:58:51.06716+08:00"},{"id":"608c00e1835ad72363ef08796961faca","path":"backend/app/config.py","line_range":"4-17","gmt_create":"2026-04-24T10:58:51.068971+08:00","gmt_modified":"2026-04-24T10:58:51.068971+08:00"},{"id":"ec4bf600a513dc2b014c85e141d7582d","path":"backend/app/workers/scheduler.py","line_range":"51-85","gmt_create":"2026-04-24T10:58:51.0746+08:00","gmt_modified":"2026-04-24T10:58:51.0746+08:00"},{"id":"9606b8243736b4a6f5ecfe152b2ab6dd","path":"backend/app/middleware/rate_limit.py","line_range":"34-83","gmt_create":"2026-04-24T10:58:51.079072+08:00","gmt_modified":"2026-04-24T10:58:51.079072+08:00"},{"id":"05664cbd35007caa5290760cc1ef1b99","path":"backend/app/api/admin.py","line_range":"29-108","gmt_create":"2026-04-24T10:58:51.079983+08:00","gmt_modified":"2026-04-24T10:58:51.079983+08:00"},{"id":"3d85cad939ce858f9c6d153d425c19fb","path":"backend/app/services/subscription.py","line_range":"25-155","gmt_create":"2026-04-24T10:58:51.081143+08:00","gmt_modified":"2026-04-24T10:58:51.081143+08:00"},{"id":"36769bd305cd5f664fa6e28f82e4b3e7","path":"backend/app/schemas/subscription.py","line_range":"1-41","gmt_create":"2026-04-24T10:58:51.08184+08:00","gmt_modified":"2026-04-24T10:58:51.08184+08:00"},{"id":"14c2d098319eeab16c64ff7d1447df6b","path":"backend/app/api/reports.py","line_range":"18-75","gmt_create":"2026-04-24T10:58:51.082903+08:00","gmt_modified":"2026-04-24T10:58:51.082904+08:00"},{"id":"1f8d26b6a5da49d89d95bb13c7ace2c6","path":"backend/app/models/user.py","line_range":"1-48","gmt_create":"2026-04-24T10:59:38.896976+08:00","gmt_modified":"2026-04-24T10:59:38.896976+08:00"},{"id":"c8f2dbcb7475bd189a34c7061ea46c6d","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","line_range":"1-41","gmt_create":"2026-04-24T10:59:38.901742+08:00","gmt_modified":"2026-04-24T10:59:38.901742+08:00"},{"id":"08c1475254a5bc8877ff29a895de3b6a","path":"backend/app/services/auth.py","line_range":"1-175","gmt_create":"2026-04-24T10:59:38.902658+08:00","gmt_modified":"2026-04-24T10:59:38.902658+08:00"},{"id":"f5978358d04c3c917d9ca5044c7f36fa","path":"backend/app/models/user.py","line_range":"11-48","gmt_create":"2026-04-24T10:59:38.903869+08:00","gmt_modified":"2026-04-24T10:59:38.903869+08:00"},{"id":"675ab6c1ae510ca753b5e966b7b6a10c","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","line_range":"21-41","gmt_create":"2026-04-24T10:59:38.907463+08:00","gmt_modified":"2026-04-24T10:59:38.907463+08:00"},{"id":"fe351bf59a46bec7f77ffe40a68a5993","path":"backend/app/services/auth.py","line_range":"40-56","gmt_create":"2026-04-24T10:59:38.917216+08:00","gmt_modified":"2026-04-24T10:59:38.917216+08:00"},{"id":"46e69841e5c5dc62faa55c9f066586d6","path":"backend/app/services/auth.py","line_range":"74-107","gmt_create":"2026-04-24T10:59:38.919469+08:00","gmt_modified":"2026-04-24T10:59:38.919469+08:00"},{"id":"cecc8857775f7928d465b68e429493d2","path":"backend/app/services/auth.py","line_range":"110-140","gmt_create":"2026-04-24T10:59:38.91977+08:00","gmt_modified":"2026-04-24T10:59:38.91977+08:00"},{"id":"1153d8a149a70bc79ca59a9dcba5945c","path":"backend/app/schemas/auth.py","line_range":"8-55","gmt_create":"2026-04-24T10:59:38.920046+08:00","gmt_modified":"2026-04-24T10:59:38.920046+08:00"},{"id":"35dd08df9c7a562d9c7b8edf740eaf3c","path":"backend/app/api/auth.py","line_range":"33-115","gmt_create":"2026-04-24T10:59:38.920424+08:00","gmt_modified":"2026-04-24T10:59:38.920424+08:00"},{"id":"dc735ee4a0f12140bcee122a67f4a13b","path":"frontend/components/layout/sidebar.tsx","line_range":"1-63","gmt_create":"2026-04-24T11:01:58.065941+08:00","gmt_modified":"2026-04-24T11:01:58.065941+08:00"},{"id":"f990ecd63842b3ab82f5b8c8dcde2a6b","path":"frontend/next.config.mjs","line_range":"1-5","gmt_create":"2026-04-24T11:01:58.066899+08:00","gmt_modified":"2026-04-24T11:01:58.0669+08:00"},{"id":"d5efa0fbc545b778dd913854d860c502","path":"frontend/types/next-auth.d.ts","line_range":"1-29","gmt_create":"2026-04-24T11:01:58.069351+08:00","gmt_modified":"2026-04-24T11:01:58.069351+08:00"},{"id":"46434c04e402674d97a6e2017a3a13c0","path":"backend/app/schemas/auth.py","line_range":"8-62","gmt_create":"2026-04-24T11:02:17.54295+08:00","gmt_modified":"2026-04-24T11:02:17.54295+08:00"},{"id":"3a0fd619768c80d413f8b02b3daec229","path":"backend/app/services/auth.py","line_range":"74-175","gmt_create":"2026-04-24T11:02:17.543584+08:00","gmt_modified":"2026-04-24T11:02:17.543584+08:00"},{"id":"86af0295eebcd62f33207e158db86c81","path":"backend/app/api/auth.py","line_range":"65-115","gmt_create":"2026-04-24T11:02:17.544119+08:00","gmt_modified":"2026-04-24T11:02:17.544119+08:00"},{"id":"809fc86e3ce390a1af1db1e0cd5ad787","path":"frontend/lib/api.ts","line_range":"55-84","gmt_create":"2026-04-24T11:02:17.544907+08:00","gmt_modified":"2026-04-24T11:02:17.544908+08:00"},{"id":"29ee02d164db08d7b9bd4591195e191b","path":"frontend/lib/auth.ts","line_range":"5-56","gmt_create":"2026-04-24T11:02:17.550558+08:00","gmt_modified":"2026-04-24T11:02:17.550559+08:00"},{"id":"73c4889fcacaea737921a568bf20383d","path":"frontend/lib/auth.ts","line_range":"13-32","gmt_create":"2026-04-24T11:02:17.552671+08:00","gmt_modified":"2026-04-24T11:02:17.552672+08:00"},{"id":"11c2505e56ba9a48c50be4c915f22c9d","path":"backend/app/services/auth.py","line_range":"27-37","gmt_create":"2026-04-24T11:02:17.554379+08:00","gmt_modified":"2026-04-24T11:02:17.554379+08:00"},{"id":"5f32b18b18cea3b2bdc9150366c24e5e","path":"backend/app/api/deps.py","line_range":"26-37","gmt_create":"2026-04-24T11:02:17.554832+08:00","gmt_modified":"2026-04-24T11:02:17.554832+08:00"},{"id":"c4abaa8a82ad75d09ee66f97fbad4b96","path":"backend/app/config.py","line_range":"9-10","gmt_create":"2026-04-24T11:02:17.555347+08:00","gmt_modified":"2026-04-24T11:02:17.555347+08:00"},{"id":"08ac91fb508b386f0e6c66e53b03a471","path":"backend/app/schemas/auth.py","line_range":"8-11","gmt_create":"2026-04-24T11:02:17.556938+08:00","gmt_modified":"2026-04-24T11:02:17.556938+08:00"},{"id":"d4ea500c0acb4ebf267a44908e23f787","path":"backend/app/services/auth.py","line_range":"40-55","gmt_create":"2026-04-24T11:02:17.557577+08:00","gmt_modified":"2026-04-24T11:02:17.557577+08:00"},{"id":"b4f0bea37f71296167571d8831ebe6d5","path":"tests/test_auth.py","line_range":"25-58","gmt_create":"2026-04-24T11:02:17.558569+08:00","gmt_modified":"2026-04-24T11:02:17.558569+08:00"},{"id":"46f7431da5eb82bbd7686a71abaddf78","path":"backend/app/api/auth.py","line_range":"42-57","gmt_create":"2026-04-24T11:02:17.558961+08:00","gmt_modified":"2026-04-24T11:02:17.558961+08:00"},{"id":"0ba2ea54873608360c48c8b5aaeea20f","path":"backend/app/services/auth.py","line_range":"58-71","gmt_create":"2026-04-24T11:02:17.559312+08:00","gmt_modified":"2026-04-24T11:02:17.559312+08:00"},{"id":"2d170933ae8c838199f6d68a2b9165c0","path":"tests/test_auth.py","line_range":"61-84","gmt_create":"2026-04-24T11:02:17.560326+08:00","gmt_modified":"2026-04-24T11:02:17.560327+08:00"},{"id":"0ea85b56099b9087bd22eec96b7bb752","path":"backend/app/services/auth.py","line_range":"74-140","gmt_create":"2026-04-24T11:02:17.560916+08:00","gmt_modified":"2026-04-24T11:02:17.560916+08:00"},{"id":"2a4087b6941ca17dd651147f2f23451c","path":"backend/app/api/auth.py","line_range":"65-90","gmt_create":"2026-04-24T11:02:17.561945+08:00","gmt_modified":"2026-04-24T11:02:17.561945+08:00"},{"id":"88c12e200d5c3ea53c695aa4209cecd9","path":"backend/app/api/auth.py","line_range":"65-76","gmt_create":"2026-04-24T11:02:17.562602+08:00","gmt_modified":"2026-04-24T11:02:17.562603+08:00"},{"id":"42b92d878423a23067e9a6da104e3a5e","path":"backend/app/api/auth.py","line_range":"79-90","gmt_create":"2026-04-24T11:02:17.564153+08:00","gmt_modified":"2026-04-24T11:02:17.564153+08:00"},{"id":"abadc99952ad6e00ab4bfb66b84732bb","path":"backend/app/schemas/auth.py","line_range":"33-41","gmt_create":"2026-04-24T11:02:17.56603+08:00","gmt_modified":"2026-04-24T11:02:17.56603+08:00"},{"id":"f784a33e47128515d518555d99103f62","path":"backend/app/services/auth.py","line_range":"143-175","gmt_create":"2026-04-24T11:02:17.566806+08:00","gmt_modified":"2026-04-24T11:02:17.566806+08:00"},{"id":"173f8de5896e18fc81cdd5d72e2a8c07","path":"backend/app/api/auth.py","line_range":"93-115","gmt_create":"2026-04-24T11:02:17.567894+08:00","gmt_modified":"2026-04-24T11:02:17.567894+08:00"},{"id":"3ab144009e705151f69698d2d8a81cea","path":"backend/app/services/auth.py","line_range":"35-37","gmt_create":"2026-04-24T11:02:17.56892+08:00","gmt_modified":"2026-04-24T11:02:17.56892+08:00"},{"id":"570a917d85850ab1208fce5823b110a3","path":"backend/app/api/auth.py","line_range":"60-62","gmt_create":"2026-04-24T11:02:17.569617+08:00","gmt_modified":"2026-04-24T11:02:17.569617+08:00"},{"id":"f92c0c41197c488f04f994bf0f7ea465","path":"tests/test_auth.py","line_range":"87-104","gmt_create":"2026-04-24T11:02:17.570008+08:00","gmt_modified":"2026-04-24T11:02:17.570008+08:00"},{"id":"5688471e2418628ac2a6409451708d06","path":"backend/app/api/auth.py","line_range":"1-115","gmt_create":"2026-04-24T11:02:17.571751+08:00","gmt_modified":"2026-04-24T11:02:17.571751+08:00"},{"id":"7075cde1c771c46dbbd37b3c09dac53d","path":"backend/app/api/deps.py","line_range":"20-41","gmt_create":"2026-04-24T11:02:17.576276+08:00","gmt_modified":"2026-04-24T11:02:17.576276+08:00"},{"id":"607e99e751640281d26516c772548b93","path":"frontend/lib/api.ts","line_range":"17-39","gmt_create":"2026-04-24T11:02:17.576883+08:00","gmt_modified":"2026-04-24T11:02:17.576883+08:00"},{"id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","path":"backend/app/main.py","line_range":"12-78","gmt_create":"2026-04-24T11:02:30.018464+08:00","gmt_modified":"2026-04-24T11:02:30.018464+08:00"},{"id":"10d3948b1394ffa0110796edfa0bfc25","path":"backend/app/api/auth.py","line_range":"30","gmt_create":"2026-04-24T11:02:30.018782+08:00","gmt_modified":"2026-04-24T11:02:30.018782+08:00"},{"id":"d6ebce8c7d9e9de127486400670ebed0","path":"backend/app/main.py","line_range":"39-84","gmt_create":"2026-04-24T11:02:30.020913+08:00","gmt_modified":"2026-04-24T11:02:30.020913+08:00"},{"id":"ec3ed02cad3cd8af4bacb5c978273092","path":"backend/app/api/subscriptions.py","line_range":"26-77","gmt_create":"2026-04-24T11:02:30.021508+08:00","gmt_modified":"2026-04-24T11:02:30.021509+08:00"},{"id":"2db9940a42c91fc92f23595491ea93d1","path":"backend/app/main.py","line_range":"67-78","gmt_create":"2026-04-24T11:02:30.022384+08:00","gmt_modified":"2026-04-24T11:02:30.022384+08:00"},{"id":"68fbb2bd365f96a98ea187a9738c4460","path":"backend/app/api/auth.py","line_range":"33-57","gmt_create":"2026-04-24T11:02:30.024114+08:00","gmt_modified":"2026-04-24T11:02:30.024114+08:00"},{"id":"44f9c9f195e096efbd6c6a6f97880944","path":"backend/app/api/reports.py","line_range":"51-75","gmt_create":"2026-04-24T11:02:30.02932+08:00","gmt_modified":"2026-04-24T11:02:30.02932+08:00"},{"id":"cbe8ffc1cfb98ac79c7659e968191837","path":"backend/app/services/citation.py","line_range":"343-466","gmt_create":"2026-04-24T11:02:30.029647+08:00","gmt_modified":"2026-04-24T11:02:30.029647+08:00"},{"id":"97f9b6149bd43feb0f69cf2582ab6305","path":"backend/app/services/subscription.py","line_range":"85-117","gmt_create":"2026-04-24T11:02:30.030707+08:00","gmt_modified":"2026-04-24T11:02:30.030707+08:00"},{"id":"ce4de96353f8f81ca825173ddbec1150","path":"backend/app/schemas/subscription.py","line_range":"12-41","gmt_create":"2026-04-24T11:02:30.031384+08:00","gmt_modified":"2026-04-24T11:02:30.031384+08:00"},{"id":"a87a1a7c1723518159d5818c197996cc","path":"backend/app/services/subscription.py","line_range":"56-155","gmt_create":"2026-04-24T11:02:30.031685+08:00","gmt_modified":"2026-04-24T11:02:30.031686+08:00"},{"id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","path":"backend/app/api/admin.py","line_range":"29-45","gmt_create":"2026-04-24T11:02:30.031966+08:00","gmt_modified":"2026-04-24T11:02:30.031966+08:00"},{"id":"f7314a4515e822cba6f37d7a8f1970f3","path":"backend/app/services/admin.py","line_range":"14-46","gmt_create":"2026-04-24T11:02:30.032241+08:00","gmt_modified":"2026-04-24T11:02:30.032242+08:00"},{"id":"ef31f4aa4fbd1b6ff76eba467b757a04","path":"backend/app/middleware/rate_limit.py","line_range":"34-69","gmt_create":"2026-04-24T11:02:30.033139+08:00","gmt_modified":"2026-04-24T11:02:30.03314+08:00"},{"id":"3a7201f4564dbcf35c5771f1b5d58cb6","path":"backend/app/api/auth.py","line_range":"46-50","gmt_create":"2026-04-24T11:02:30.037193+08:00","gmt_modified":"2026-04-24T11:02:30.037193+08:00"},{"id":"39c3dbe67ab2ae74446fe6a118bd8738","path":"backend/app/api/reports.py","line_range":"25-29","gmt_create":"2026-04-24T11:02:30.038125+08:00","gmt_modified":"2026-04-24T11:02:30.038125+08:00"},{"id":"68d937267aab2509edc0c7b67e1b5ef6","path":"backend/app/api/subscriptions.py","line_range":"53-57","gmt_create":"2026-04-24T11:02:30.038578+08:00","gmt_modified":"2026-04-24T11:02:30.038578+08:00"},{"id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","path":"backend/app/api/admin.py","line_range":"22-25","gmt_create":"2026-04-24T11:02:30.038936+08:00","gmt_modified":"2026-04-24T11:02:30.038936+08:00"},{"id":"a9c1b0716ae36af22fce6148c2e40ce5","path":"backend/app/middleware/rate_limit.py","line_range":"47-49","gmt_create":"2026-04-24T11:02:30.039285+08:00","gmt_modified":"2026-04-24T11:02:30.039285+08:00"},{"id":"461200c8ca02024dd32c214c679b9664","path":"backend/app/agent_framework/agents/content_generator_agent.py","line_range":"1-299","gmt_create":"2026-05-23T15:16:36.150133+08:00","gmt_modified":"2026-05-23T15:16:36.150133+08:00"},{"id":"7f44b646183e17098f8ce4d2be931d3e","path":"backend/app/agent_framework/agents/deai_agent.py","line_range":"1-156","gmt_create":"2026-05-23T15:16:36.15079+08:00","gmt_modified":"2026-05-23T15:16:36.15079+08:00"},{"id":"45778eaa35d92099677ba180f1067905","path":"backend/app/agent_framework/agents/geo_optimizer_agent.py","line_range":"1-198","gmt_create":"2026-05-23T15:16:36.151168+08:00","gmt_modified":"2026-05-23T15:16:36.151168+08:00"},{"id":"74bf1d1b17dff651c44a2f4dc12d7bc7","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"1-536","gmt_create":"2026-05-23T15:16:36.151542+08:00","gmt_modified":"2026-05-23T15:16:36.151542+08:00"},{"id":"d8a98dd989912e358f7dbd278e1c5353","path":"backend/app/agent_framework/pipeline/loader.py","line_range":"1-283","gmt_create":"2026-05-23T15:16:36.152324+08:00","gmt_modified":"2026-05-23T15:16:36.152324+08:00"},{"id":"3d0cd79c03fc72299fb184947c5d0d6c","path":"backend/app/services/llm/factory.py","line_range":"1-66","gmt_create":"2026-05-23T15:16:36.152776+08:00","gmt_modified":"2026-05-23T15:16:36.152776+08:00"},{"id":"c43dadd2749edf2a89b29068d7644bb9","path":"tests/test_content_agents.py","line_range":"26-54","gmt_create":"2026-05-23T15:16:36.155935+08:00","gmt_modified":"2026-05-23T15:16:36.155935+08:00"},{"id":"3251d42aeb8cbe7f90d0e9827fbecdb8","path":"tests/test_pipeline_engine.py","line_range":"148-166","gmt_create":"2026-05-23T15:16:36.156829+08:00","gmt_modified":"2026-05-23T15:16:36.156829+08:00"},{"id":"8cdfa09247c1ca69fa5581194d1dc998","path":"tests/test_content_agents.py","line_range":"75-116","gmt_create":"2026-05-23T15:16:36.17723+08:00","gmt_modified":"2026-05-23T15:16:36.177231+08:00"},{"id":"4d43427ff0dc504c0665bd3e3f86d68c","path":"tests/test_content_agents.py","line_range":"200-236","gmt_create":"2026-05-23T15:16:36.178007+08:00","gmt_modified":"2026-05-23T15:16:36.178008+08:00"},{"id":"7ec53d0bb9dd7a59cedbd4d3865fddf8","path":"tests/test_content_agents.py","line_range":"268-320","gmt_create":"2026-05-23T15:16:36.178749+08:00","gmt_modified":"2026-05-23T15:16:36.178749+08:00"},{"id":"67b04d8d66c36c9362f3c42260f08d77","path":"tests/test_content_agents.py","line_range":"1-358","gmt_create":"2026-05-23T15:16:36.179312+08:00","gmt_modified":"2026-05-23T15:16:36.179312+08:00"},{"id":"a29fa4c505649339b1a61e2bd730e05a","path":"tests/test_llm_provider.py","line_range":"24-67","gmt_create":"2026-05-23T15:16:36.181057+08:00","gmt_modified":"2026-05-23T15:16:36.181057+08:00"},{"id":"892c4889ccac1ebb4f9871633c633fb0","path":"tests/test_llm_provider.py","line_range":"94-153","gmt_create":"2026-05-23T15:16:36.181436+08:00","gmt_modified":"2026-05-23T15:16:36.181436+08:00"},{"id":"5a90244fc04639f59621ea190b395d53","path":"tests/test_llm_provider.py","line_range":"200-204","gmt_create":"2026-05-23T15:16:36.18181+08:00","gmt_modified":"2026-05-23T15:16:36.18181+08:00"},{"id":"7a5c445db631fd099bd752645fe46eeb","path":"backend/app/services/llm/factory.py","line_range":"8-66","gmt_create":"2026-05-23T15:16:36.182157+08:00","gmt_modified":"2026-05-23T15:16:36.182157+08:00"},{"id":"470e94b38cfbc9bfa40075043a5ff609","path":"tests/test_llm_provider.py","line_range":"1-205","gmt_create":"2026-05-23T15:16:36.182504+08:00","gmt_modified":"2026-05-23T15:16:36.182504+08:00"},{"id":"e2014a3633197a028b389f084f136010","path":"tests/test_pipeline_engine.py","line_range":"55-98","gmt_create":"2026-05-23T15:16:36.18324+08:00","gmt_modified":"2026-05-23T15:16:36.183241+08:00"},{"id":"4d80ca6fa9f1355807471a059213113a","path":"tests/test_pipeline_engine.py","line_range":"148-223","gmt_create":"2026-05-23T15:16:36.183606+08:00","gmt_modified":"2026-05-23T15:16:36.183606+08:00"},{"id":"1c16d98271c83e4d1bf7759d6eff90e7","path":"backend/app/agent_framework/pipeline/loader.py","line_range":"41-134","gmt_create":"2026-05-23T15:16:36.183951+08:00","gmt_modified":"2026-05-23T15:16:36.183951+08:00"},{"id":"32e64c6a06a68a4c10f248296033c62e","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"31-176","gmt_create":"2026-05-23T15:16:36.184299+08:00","gmt_modified":"2026-05-23T15:16:36.184299+08:00"},{"id":"a593c13b0e0e255b16b161d69fcd4c09","path":"tests/test_pipeline_engine.py","line_range":"1-255","gmt_create":"2026-05-23T15:16:36.184645+08:00","gmt_modified":"2026-05-23T15:16:36.184646+08:00"},{"id":"7a0c4604142743b83dfb37f2ff1aa3e8","path":"backend/tests/test_integration/test_full_flow.py","line_range":"94-223","gmt_create":"2026-05-23T15:16:36.186659+08:00","gmt_modified":"2026-05-23T15:16:36.18666+08:00"},{"id":"3548385bba6b1c5a95d40191fbb95fc4","path":"backend/tests/test_integration/test_full_flow.py","line_range":"228-298","gmt_create":"2026-05-23T15:16:36.187173+08:00","gmt_modified":"2026-05-23T15:16:36.187174+08:00"},{"id":"4c439b670fff499e1277c271ed2e3598","path":"backend/tests/test_integration/test_full_flow.py","line_range":"1-322","gmt_create":"2026-05-23T15:16:36.187672+08:00","gmt_modified":"2026-05-23T15:16:36.187672+08:00"},{"id":"0a5c3d0a239107364b77b52d4ff33454","path":"backend/app/api/agents.py","line_range":"29","gmt_create":"2026-05-23T15:17:24.09425+08:00","gmt_modified":"2026-05-23T15:17:24.09425+08:00"},{"id":"6c9ecb8d32dfd5ce9b2dc95f1a110d97","path":"backend/app/api/analytics.py","line_range":"26","gmt_create":"2026-05-23T15:17:24.095854+08:00","gmt_modified":"2026-05-23T15:17:24.095854+08:00"},{"id":"6242be39e66058ce4f2dd93974e98599","path":"backend/app/api/lifecycle.py","line_range":"24","gmt_create":"2026-05-23T15:17:24.096741+08:00","gmt_modified":"2026-05-23T15:17:24.096741+08:00"},{"id":"3dde6ad029645735cef7c4edf22b28c3","path":"backend/app/api/knowledge.py","line_range":"38","gmt_create":"2026-05-23T15:17:24.097406+08:00","gmt_modified":"2026-05-23T15:17:24.097406+08:00"},{"id":"c7cbd948815aa81602e95e7e469a2b80","path":"backend/app/api/agents.py","line_range":"66-299","gmt_create":"2026-05-23T15:17:24.099768+08:00","gmt_modified":"2026-05-23T15:17:24.099769+08:00"},{"id":"c666a867c1b927bcc12241a45e84cd71","path":"backend/app/api/analytics.py","line_range":"47-243","gmt_create":"2026-05-23T15:17:24.100264+08:00","gmt_modified":"2026-05-23T15:17:24.100264+08:00"},{"id":"196c325b93526e566ba9f2560a82c2ac","path":"backend/app/api/lifecycle.py","line_range":"85-297","gmt_create":"2026-05-23T15:17:24.100674+08:00","gmt_modified":"2026-05-23T15:17:24.100674+08:00"},{"id":"f617a59447265c18ad5d4c79e9db8e12","path":"backend/app/api/knowledge.py","line_range":"81-502","gmt_create":"2026-05-23T15:17:24.101317+08:00","gmt_modified":"2026-05-23T15:17:24.101318+08:00"},{"id":"ffb5c89d546d3895e7ac0ed320a6ed90","path":"backend/app/api/agents.py","line_range":"186-222","gmt_create":"2026-05-23T15:17:24.127315+08:00","gmt_modified":"2026-05-23T15:17:24.127315+08:00"},{"id":"e6fe884abc694714e2eb8bf1be27d72b","path":"backend/app/models/agent.py","line_range":"98-155","gmt_create":"2026-05-23T15:17:24.128304+08:00","gmt_modified":"2026-05-23T15:17:24.128304+08:00"},{"id":"ebc123c07512c5d5aeb1011d228a895c","path":"backend/app/models/agent.py","line_range":"12-206","gmt_create":"2026-05-23T15:17:24.129859+08:00","gmt_modified":"2026-05-23T15:17:24.129859+08:00"},{"id":"9cbf60c1b6ff2f8c74be2f168f4f44eb","path":"backend/app/api/analytics.py","line_range":"47-60","gmt_create":"2026-05-23T15:17:24.130699+08:00","gmt_modified":"2026-05-23T15:17:24.130699+08:00"},{"id":"eb865aa7324cbb6c6ec83cf884c36b98","path":"backend/app/api/analytics.py","line_range":"206-212","gmt_create":"2026-05-23T15:17:24.131272+08:00","gmt_modified":"2026-05-23T15:17:24.131272+08:00"},{"id":"68580333c31256edc20b45d90197222c","path":"backend/app/schemas/analytics.py","line_range":"14-145","gmt_create":"2026-05-23T15:17:24.13239+08:00","gmt_modified":"2026-05-23T15:17:24.13239+08:00"},{"id":"98d6d7fe81309b5f48907ff2c96bd9e9","path":"backend/app/api/lifecycle.py","line_range":"190-230","gmt_create":"2026-05-23T15:17:24.133293+08:00","gmt_modified":"2026-05-23T15:17:24.133293+08:00"},{"id":"4d98c570e47fa5aa35c93cc23d9a9531","path":"backend/app/schemas/lifecycle.py","line_range":"9-68","gmt_create":"2026-05-23T15:17:24.134291+08:00","gmt_modified":"2026-05-23T15:17:24.134291+08:00"},{"id":"6a2a5a7cb69cc0e72c2e90e1d9e48037","path":"backend/app/models/lifecycle.py","line_range":"12-92","gmt_create":"2026-05-23T15:17:24.134691+08:00","gmt_modified":"2026-05-23T15:17:24.134692+08:00"},{"id":"f38b21f300a72d77625c203e8d9e5916","path":"backend/app/api/knowledge.py","line_range":"424-501","gmt_create":"2026-05-23T15:17:24.135099+08:00","gmt_modified":"2026-05-23T15:17:24.135099+08:00"},{"id":"02ee224326bf5a0307c63b44ccb270ac","path":"backend/app/schemas/knowledge.py","line_range":"9-77","gmt_create":"2026-05-23T15:17:24.135982+08:00","gmt_modified":"2026-05-23T15:17:24.135983+08:00"},{"id":"f043b2767c713f94381e9f7154cd904a","path":"backend/app/models/knowledge.py","line_range":"22-213","gmt_create":"2026-05-23T15:17:24.136389+08:00","gmt_modified":"2026-05-23T15:17:24.136389+08:00"},{"id":"934240d46ff47296dae2c8aef650b86f","path":"backend/app/api/agents.py","line_range":"84-88","gmt_create":"2026-05-23T15:17:24.153907+08:00","gmt_modified":"2026-05-23T15:17:24.153907+08:00"},{"id":"be2989f88e1e49d5282ec7353c9c4e89","path":"backend/app/api/analytics.py","line_range":"36-40","gmt_create":"2026-05-23T15:17:24.154515+08:00","gmt_modified":"2026-05-23T15:17:24.154515+08:00"},{"id":"3b33430ff6a3ac8b10af49dc35af8231","path":"backend/app/api/lifecycle.py","line_range":"146","gmt_create":"2026-05-23T15:17:24.155164+08:00","gmt_modified":"2026-05-23T15:17:24.155164+08:00"},{"id":"59b4deade567af54c91f1a162e57b5be","path":"backend/app/api/knowledge.py","line_range":"92-96","gmt_create":"2026-05-23T15:17:24.155766+08:00","gmt_modified":"2026-05-23T15:17:24.155766+08:00"},{"id":"6171fd1748ad5189394ba670000e7e75","path":"frontend/package.json","line_range":"1-45","gmt_create":"2026-05-23T15:18:41.062838+08:00","gmt_modified":"2026-05-23T15:18:41.062838+08:00"},{"id":"00502fc9ffc15147665f96f056735d74","path":"backend/requirements.txt","line_range":"1-42","gmt_create":"2026-05-23T15:18:41.064091+08:00","gmt_modified":"2026-05-23T15:18:41.064092+08:00"},{"id":"dd36901ce62b8cc1d66667dcdc45e637","path":"backend/app/config.py","line_range":"1-46","gmt_create":"2026-05-23T15:18:41.071093+08:00","gmt_modified":"2026-05-23T15:18:41.071093+08:00"},{"id":"36ca3ba8293eaed314a7628b0272e957","path":"frontend/.eslintrc.json","line_range":"1-14","gmt_create":"2026-05-23T15:18:41.088084+08:00","gmt_modified":"2026-05-23T15:18:41.088084+08:00"},{"id":"03b024618527c930185a98873f353b45","path":"backend/app/config.py","line_range":"12-18","gmt_create":"2026-05-23T15:18:41.091753+08:00","gmt_modified":"2026-05-23T15:18:41.091753+08:00"},{"id":"1693d293c428ed4a66bd90519a1bbad5","path":"backend/app/config.py","line_range":"12-13","gmt_create":"2026-05-23T15:18:41.103505+08:00","gmt_modified":"2026-05-23T15:18:41.103505+08:00"},{"id":"c4f552eaa67bc052a06af7e5399d954c","path":"backend/app/config.py","line_range":"9-46","gmt_create":"2026-05-23T15:18:41.11012+08:00","gmt_modified":"2026-05-23T15:18:41.11012+08:00"},{"id":"db1c839ece4f3899017126c9b5b36016","path":"docs/03-development/coding-standards.md","line_range":"1-29","gmt_create":"2026-05-23T15:18:41.114928+08:00","gmt_modified":"2026-05-23T15:18:41.114928+08:00"},{"id":"9efa352ff057d696763b5eca047c0ca1","path":"docs/03-development/dev-guide.md","line_range":"1-32","gmt_create":"2026-05-23T15:18:41.116419+08:00","gmt_modified":"2026-05-23T15:18:41.11642+08:00"},{"id":"10a5c824715b3c199eb40e1531c64150","path":"docs/03-development/tdd-workflow.md","line_range":"1-583","gmt_create":"2026-05-23T15:18:41.118231+08:00","gmt_modified":"2026-05-23T15:18:41.118231+08:00"},{"id":"a47a364b551a984436d38cc17a272ef5","path":"docs/04-testing/test-strategy.md","line_range":"1-33","gmt_create":"2026-05-23T15:18:41.118882+08:00","gmt_modified":"2026-05-23T15:18:41.118882+08:00"},{"id":"6d2bbc04de724a57683b6d1af6f76e5b","path":"docs/05-deployment/deployment-guide.md","line_range":"1-32","gmt_create":"2026-05-23T15:18:41.11976+08:00","gmt_modified":"2026-05-23T15:18:41.11976+08:00"},{"id":"67f5802e0fa695697eb6eeb1d1071448","path":"docs/00-project/tech-stack.md","line_range":"1-71","gmt_create":"2026-05-23T15:18:41.123994+08:00","gmt_modified":"2026-05-23T15:18:41.123994+08:00"},{"id":"87eaeed0bc611204a7529b148ae846e2","path":"backend/app/models/lifecycle.py","line_range":"1-92","gmt_create":"2026-05-23T15:19:23.483625+08:00","gmt_modified":"2026-05-23T15:19:23.483626+08:00"},{"id":"790fb08a04a977bb97a81ea19d785777","path":"backend/app/models/analytics.py","line_range":"1-64","gmt_create":"2026-05-23T15:19:23.48412+08:00","gmt_modified":"2026-05-23T15:19:23.48412+08:00"},{"id":"7bf4a8a5aa73c1704f76f4947a1a327a","path":"backend/app/models/alert.py","line_range":"1-75","gmt_create":"2026-05-23T15:19:23.484664+08:00","gmt_modified":"2026-05-23T15:19:23.484664+08:00"},{"id":"9b03c2a2c7f00f40338248fa6d6f5c8b","path":"backend/app/models/knowledge.py","line_range":"1-213","gmt_create":"2026-05-23T15:19:23.485069+08:00","gmt_modified":"2026-05-23T15:19:23.485069+08:00"},{"id":"d15e1f6c18afa7505178062959fe7333","path":"backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","line_range":"1-398","gmt_create":"2026-05-23T15:19:23.493615+08:00","gmt_modified":"2026-05-23T15:19:23.493616+08:00"},{"id":"762a2f675ceac5ab98af9a601f886b64","path":"backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py","line_range":"1-125","gmt_create":"2026-05-23T15:19:23.49436+08:00","gmt_modified":"2026-05-23T15:19:23.494361+08:00"},{"id":"2df394b949344fe9ab2c77227b91a836","path":"backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","line_range":"1-86","gmt_create":"2026-05-23T15:19:23.494948+08:00","gmt_modified":"2026-05-23T15:19:23.494949+08:00"},{"id":"0dc739a646e968be4ef81f8d6f73172f","path":"backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py","line_range":"1-224","gmt_create":"2026-05-23T15:19:23.495801+08:00","gmt_modified":"2026-05-23T15:19:23.495802+08:00"},{"id":"867308b1867163b86fcf5da125bff7bd","path":"backend/app/models/analytics.py","line_range":"9-64","gmt_create":"2026-05-23T15:19:23.500977+08:00","gmt_modified":"2026-05-23T15:19:23.500977+08:00"},{"id":"7bb1fe5eea543a455c000decbf835a87","path":"backend/app/models/alert.py","line_range":"24-75","gmt_create":"2026-05-23T15:19:23.50143+08:00","gmt_modified":"2026-05-23T15:19:23.50143+08:00"},{"id":"14d45085df87325a1a8a05e5a7306ea9","path":"backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","line_range":"24-398","gmt_create":"2026-05-23T15:19:23.507299+08:00","gmt_modified":"2026-05-23T15:19:23.507299+08:00"},{"id":"ab4062f7b12bddc89c8a6ecb5716ec22","path":"backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py","line_range":"24-125","gmt_create":"2026-05-23T15:19:23.508028+08:00","gmt_modified":"2026-05-23T15:19:23.508028+08:00"},{"id":"d8c1ac7c70dcfce3893bb34ccad2ea86","path":"backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","line_range":"24-86","gmt_create":"2026-05-23T15:19:23.508459+08:00","gmt_modified":"2026-05-23T15:19:23.50846+08:00"},{"id":"3f54e06cbaf0717d01fb0f4cb7294795","path":"backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py","line_range":"30-224","gmt_create":"2026-05-23T15:19:23.509955+08:00","gmt_modified":"2026-05-23T15:19:23.509955+08:00"},{"id":"948aa417b68df80b5de0cfdb37e5455e","path":"backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","line_range":"21-398","gmt_create":"2026-05-23T15:19:23.520133+08:00","gmt_modified":"2026-05-23T15:19:23.520133+08:00"},{"id":"96de5ca994afbb0cc75f2b0d419d69f7","path":"backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","line_range":"21-86","gmt_create":"2026-05-23T15:19:23.520982+08:00","gmt_modified":"2026-05-23T15:19:23.520983+08:00"},{"id":"5f830240a0d18e5b3718cd8cabebed6e","path":"backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py","line_range":"21-224","gmt_create":"2026-05-23T15:19:23.521489+08:00","gmt_modified":"2026-05-23T15:19:23.521489+08:00"},{"id":"4a7611bf0d84c8d44518673bbe5af6ad","path":"backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py","line_range":"20-125","gmt_create":"2026-05-23T15:19:23.521904+08:00","gmt_modified":"2026-05-23T15:19:23.521904+08:00"},{"id":"cb292fb9d8227e14f98eed613b793a74","path":"backend/app/main.py","line_range":"1-100","gmt_create":"2026-05-23T15:19:55.736691+08:00","gmt_modified":"2026-05-23T15:19:55.736691+08:00"},{"id":"1aa2eb624a63acddcd9638630606b2e9","path":"backend/app/workers/scheduler.py","line_range":"1-189","gmt_create":"2026-05-23T15:19:55.738809+08:00","gmt_modified":"2026-05-23T15:19:55.738809+08:00"},{"id":"a03d722c5d84b49db41742b78679a2f8","path":"docker-compose.yml","line_range":"36-66","gmt_create":"2026-05-23T15:19:55.748044+08:00","gmt_modified":"2026-05-23T15:19:55.748045+08:00"},{"id":"f7e662afe370f458b73886fe90709a23","path":"backend/app/main.py","line_range":"97-100","gmt_create":"2026-05-23T15:19:55.748518+08:00","gmt_modified":"2026-05-23T15:19:55.748519+08:00"},{"id":"50925c15ef4105b22c55cd16d44103a1","path":"backend/app/main.py","line_range":"33-45","gmt_create":"2026-05-23T15:19:55.749705+08:00","gmt_modified":"2026-05-23T15:19:55.749705+08:00"},{"id":"6d4024210922cde4cb5f7944996640c5","path":"backend/app/config.py","line_range":"12-14","gmt_create":"2026-05-23T15:19:55.750168+08:00","gmt_modified":"2026-05-23T15:19:55.750169+08:00"},{"id":"b32f57d9055ac4c655dfc976b1fd51a4","path":"backend/app/workers/scheduler.py","line_range":"33-51","gmt_create":"2026-05-23T15:19:55.751771+08:00","gmt_modified":"2026-05-23T15:19:55.751771+08:00"},{"id":"60f56d5de44cd7f96dbf71d74290910d","path":"backend/app/main.py","line_range":"53-63","gmt_create":"2026-05-23T15:19:55.756309+08:00","gmt_modified":"2026-05-23T15:19:55.756309+08:00"},{"id":"0d92cb154d0e27b75793e9a25e3211c4","path":"backend/alembic.ini","line_range":"86-89","gmt_create":"2026-05-23T15:19:55.757947+08:00","gmt_modified":"2026-05-23T15:19:55.757948+08:00"},{"id":"13b13aa0fd51de34b0cfb27187df0eb0","path":"backend/app/config.py","line_range":"14","gmt_create":"2026-05-23T15:19:55.76513+08:00","gmt_modified":"2026-05-23T15:19:55.76513+08:00"},{"id":"dfaa01739b500883c182fe0ee7b38f02","path":"backend/requirements.txt","line_range":"35-42","gmt_create":"2026-05-23T15:19:55.774961+08:00","gmt_modified":"2026-05-23T15:19:55.774961+08:00"},{"id":"ffb7b526b388c92bf932d701fee71671","path":"backend/alembic/env.py","line_range":"64-89","gmt_create":"2026-05-23T15:19:55.781247+08:00","gmt_modified":"2026-05-23T15:19:55.781247+08:00"},{"id":"8b7ecdb77bf7d73f30b64d82972bf1f5","path":"frontend/tailwind.config.ts","line_range":"1-121","gmt_create":"2026-05-23T15:22:58.307417+08:00","gmt_modified":"2026-05-23T15:22:58.307417+08:00"},{"id":"a8bbf13a4b60cc33fd76c99c6bd6b36f","path":"frontend/playwright.config.ts","line_range":"1-39","gmt_create":"2026-05-23T15:22:58.309871+08:00","gmt_modified":"2026-05-23T15:22:58.309871+08:00"},{"id":"8ca9b37cfe665abc053e0258b0d036d4","path":"frontend/components/business/index.ts","line_range":"1-29","gmt_create":"2026-05-23T15:22:58.310692+08:00","gmt_modified":"2026-05-23T15:22:58.310692+08:00"},{"id":"76edaefb3ec9610b238b448a797795a1","path":"frontend/e2e/tests/dashboard-health.spec.ts","line_range":"1-264","gmt_create":"2026-05-23T15:22:58.349241+08:00","gmt_modified":"2026-05-23T15:22:58.349241+08:00"},{"id":"c413ca9685496f180a8e469f24ed082f","path":"frontend/e2e/tests/login.spec.ts","line_range":"1-126","gmt_create":"2026-05-23T15:22:58.351302+08:00","gmt_modified":"2026-05-23T15:22:58.351303+08:00"},{"id":"912411178607f349a732c3e67dccf631","path":"frontend/e2e/pages/login.page.ts","line_range":"1-36","gmt_create":"2026-05-23T15:22:58.390493+08:00","gmt_modified":"2026-05-23T15:22:58.390493+08:00"},{"id":"4f2c0f1deb411b6b716e7cd04f42a519","path":"frontend/e2e/pages/dashboard.page.ts","line_range":"1-74","gmt_create":"2026-05-23T15:22:58.391143+08:00","gmt_modified":"2026-05-23T15:22:58.391144+08:00"},{"id":"05a55dacbbd018dc394fa656f4e06a62","path":"frontend/components/business/agent-status-card.tsx","line_range":"1-134","gmt_create":"2026-05-23T15:22:58.392949+08:00","gmt_modified":"2026-05-23T15:22:58.39295+08:00"},{"id":"554c0874b68d357f426fe79db129ea9f","path":"frontend/components/business/alert-card.tsx","line_range":"1-203","gmt_create":"2026-05-23T15:22:58.394029+08:00","gmt_modified":"2026-05-23T15:22:58.394029+08:00"},{"id":"d592b986bbd1c67a5932c77ea0341bed","path":"backend/app/api/reports.py","line_range":"1-47","gmt_create":"2026-05-23T15:23:21.384011+08:00","gmt_modified":"2026-05-23T15:23:21.384011+08:00"},{"id":"d2a5fdb4be830adefb3b04de2c90f204","path":"backend/app/api/lifecycle.py","line_range":"1-297","gmt_create":"2026-05-23T15:23:21.385978+08:00","gmt_modified":"2026-05-23T15:23:21.385979+08:00"},{"id":"23914bed50c54bb11234aa5819aec0df","path":"backend/app/api/knowledge.py","line_range":"1-502","gmt_create":"2026-05-23T15:23:21.387916+08:00","gmt_modified":"2026-05-23T15:23:21.387917+08:00"},{"id":"2014cd6665b187d6dccb007539278ae7","path":"backend/app/services/analytics/tracker.py","line_range":"1-230","gmt_create":"2026-05-23T15:23:21.392304+08:00","gmt_modified":"2026-05-23T15:23:21.392304+08:00"},{"id":"451a0398486fbfcc669dc4e50c9ad6e2","path":"backend/app/services/analytics/insights.py","line_range":"1-313","gmt_create":"2026-05-23T15:23:21.393333+08:00","gmt_modified":"2026-05-23T15:23:21.393333+08:00"},{"id":"897891ede0baa5b92d1b9f030a781753","path":"backend/app/services/knowledge/rag_service.py","line_range":"1-43","gmt_create":"2026-05-23T15:23:21.394491+08:00","gmt_modified":"2026-05-23T15:23:21.394491+08:00"},{"id":"ba54afe1867c2fa2046f8f62ad1caf3c","path":"backend/app/agent_framework/agents/__init__.py","line_range":"1-14","gmt_create":"2026-05-23T15:23:21.396278+08:00","gmt_modified":"2026-05-23T15:23:21.396278+08:00"},{"id":"5dd1642d800053635d9827e12e6ea120","path":"backend/app/agent_framework/dispatcher.py","line_range":"1-367","gmt_create":"2026-05-23T15:23:21.401816+08:00","gmt_modified":"2026-05-23T15:23:21.401816+08:00"},{"id":"fa6144407f88a3c04dfcbac3b39bf8b1","path":"backend/app/models/lifecycle.py","line_range":"1-91","gmt_create":"2026-05-23T15:23:21.406648+08:00","gmt_modified":"2026-05-23T15:23:21.406648+08:00"},{"id":"78d92049eebb9a8ceb231e7d2308aa78","path":"backend/app/models/knowledge.py","line_range":"1-43","gmt_create":"2026-05-23T15:23:21.408411+08:00","gmt_modified":"2026-05-23T15:23:21.408411+08:00"},{"id":"9aac0f12a7ab3ebafd07a8bc408dbdcd","path":"backend/workers/scheduler.py","line_range":"1-95","gmt_create":"2026-05-23T15:23:21.409388+08:00","gmt_modified":"2026-05-23T15:23:21.409389+08:00"},{"id":"00a305280b8ae4fb67df733a6d4c0c89","path":"backend/workers/citation_engine.py","line_range":"1-309","gmt_create":"2026-05-23T15:23:21.40999+08:00","gmt_modified":"2026-05-23T15:23:21.40999+08:00"},{"id":"68338b3901163c41ed55d1ce10ea219a","path":"backend/workers/scheduler.py","line_range":"51-84","gmt_create":"2026-05-23T15:23:21.452583+08:00","gmt_modified":"2026-05-23T15:23:21.452583+08:00"},{"id":"0bc629b80b2505420d45840e98a2b92d","path":"backend/workers/citation_engine.py","line_range":"159-234","gmt_create":"2026-05-23T15:23:21.45373+08:00","gmt_modified":"2026-05-23T15:23:21.453731+08:00"},{"id":"f90f382f226eeca8bb1c111d10941fa0","path":"backend/app/agent_framework/dispatcher.py","line_range":"54-117","gmt_create":"2026-05-23T15:23:21.455605+08:00","gmt_modified":"2026-05-23T15:23:21.455605+08:00"},{"id":"8ece81c4077ec3e9c702e5e1092119a2","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"51-176","gmt_create":"2026-05-23T15:23:21.456738+08:00","gmt_modified":"2026-05-23T15:23:21.456738+08:00"},{"id":"168f54bd5cbe07c656ec3905e567862c","path":"backend/app/workers/citation_engine.py","line_range":"291-300","gmt_create":"2026-05-23T15:23:21.472842+08:00","gmt_modified":"2026-05-23T15:23:21.472842+08:00"},{"id":"d3e817d678735f63b277894d26626924","path":"backend/app/workers/platforms/base.py","line_range":"10-17","gmt_create":"2026-05-23T15:23:21.491085+08:00","gmt_modified":"2026-05-23T15:23:21.491085+08:00"},{"id":"f0421deca067a246711e95817e1f1b1a","path":"backend/app/workers/citation_engine.py","line_range":"151-157","gmt_create":"2026-05-23T15:23:21.493895+08:00","gmt_modified":"2026-05-23T15:23:21.493895+08:00"},{"id":"6a21ee5392ba55b57659d404ebf5355e","path":"backend/app/agent_framework/agents/citation_detector.py","line_range":"24-218","gmt_create":"2026-05-23T15:23:21.495149+08:00","gmt_modified":"2026-05-23T15:23:21.49515+08:00"},{"id":"76381105cd13daa99ac6376cfdab39f0","path":"backend/app/agent_framework/agents/content_generator_agent.py","line_range":"23-299","gmt_create":"2026-05-23T15:23:21.496545+08:00","gmt_modified":"2026-05-23T15:23:21.496545+08:00"},{"id":"ff0389ece7f710d431371a409553989c","path":"backend/app/agent_framework/agents/deai_agent.py","line_range":"21-156","gmt_create":"2026-05-23T15:23:21.497794+08:00","gmt_modified":"2026-05-23T15:23:21.497794+08:00"},{"id":"f30316a028f81ac1c0e2f77568ba64f5","path":"backend/app/agent_framework/agents/geo_optimizer_agent.py","line_range":"23-198","gmt_create":"2026-05-23T15:23:21.49926+08:00","gmt_modified":"2026-05-23T15:23:21.499261+08:00"},{"id":"72c6b8f0be1248c2ce6e84247e81416d","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"31-536","gmt_create":"2026-05-23T15:23:21.500251+08:00","gmt_modified":"2026-05-23T15:23:21.500252+08:00"},{"id":"af5a9cdc724669f93a0f9f1dd790717b","path":"backend/app/agent_framework/dispatcher.py","line_range":"32-367","gmt_create":"2026-05-23T15:23:21.501171+08:00","gmt_modified":"2026-05-23T15:23:21.501171+08:00"},{"id":"8e264e08029549dd5af31f4238522cc1","path":"backend/app/agent_framework/agents/citation_detector.py","line_range":"1-218","gmt_create":"2026-05-23T15:23:21.502734+08:00","gmt_modified":"2026-05-23T15:23:21.502734+08:00"},{"id":"12b7988890a9e461cbccd36564a6cc82","path":"backend/app/api/lifecycle.py","line_range":"138-187","gmt_create":"2026-05-23T15:23:21.511092+08:00","gmt_modified":"2026-05-23T15:23:21.511092+08:00"},{"id":"5c9cde497ea1c98e6fe63e808f1d8ca5","path":"backend/app/models/lifecycle.py","line_range":"12-91","gmt_create":"2026-05-23T15:23:21.513446+08:00","gmt_modified":"2026-05-23T15:23:21.513447+08:00"},{"id":"058be4ad1752d83067d65bf59f958461","path":"frontend/lib/api/lifecycle.ts","line_range":"53-95","gmt_create":"2026-05-23T15:23:21.51664+08:00","gmt_modified":"2026-05-23T15:23:21.51664+08:00"},{"id":"c549a2efc417d5646c81a100701cf72a","path":"backend/app/services/analytics/tracker.py","line_range":"16-51","gmt_create":"2026-05-23T15:23:21.517746+08:00","gmt_modified":"2026-05-23T15:23:21.517747+08:00"},{"id":"33c1014641412422e2687463885aef5f","path":"backend/app/services/analytics/insights.py","line_range":"40-103","gmt_create":"2026-05-23T15:23:21.518793+08:00","gmt_modified":"2026-05-23T15:23:21.518794+08:00"},{"id":"befab5441502d9e867d85550072130fa","path":"backend/app/services/analytics/tracker.py","line_range":"53-128","gmt_create":"2026-05-23T15:23:21.520036+08:00","gmt_modified":"2026-05-23T15:23:21.520036+08:00"},{"id":"1d1a90f9679ff5937c688d465591a0ab","path":"backend/app/api/knowledge.py","line_range":"217-293","gmt_create":"2026-05-23T15:23:21.523435+08:00","gmt_modified":"2026-05-23T15:23:21.523436+08:00"},{"id":"7f9b9025f56d8baba8136ab1b8ed49b3","path":"backend/app/services/knowledge/rag_service.py","line_range":"33-43","gmt_create":"2026-05-23T15:23:21.537403+08:00","gmt_modified":"2026-05-23T15:23:21.537403+08:00"},{"id":"16f20ee7078a57c6910a20d49deb646f","path":"frontend/components/charts/trend-chart.tsx","line_range":"22-59","gmt_create":"2026-05-23T15:23:21.544768+08:00","gmt_modified":"2026-05-23T15:23:21.544768+08:00"},{"id":"f457c5ae12bb63dcd5d83e4ede8efb15","path":"backend/app/api/citations.py","line_range":"49-56","gmt_create":"2026-05-23T15:23:21.546995+08:00","gmt_modified":"2026-05-23T15:23:21.546996+08:00"},{"id":"cb57298d603df7c5572310807b629516","path":"backend/app/services/citation.py","line_range":"76-201","gmt_create":"2026-05-23T15:23:21.549395+08:00","gmt_modified":"2026-05-23T15:23:21.549395+08:00"},{"id":"84d5ec753cc381b480dfd2cc2f4228a0","path":"backend/app/services/citation.py","line_range":"237-268","gmt_create":"2026-05-23T15:23:21.557366+08:00","gmt_modified":"2026-05-23T15:23:21.557366+08:00"},{"id":"d49ddf2ff36cff1ba6702d9fe3bd253d","path":"backend/app/agent_framework/dispatcher.py","line_range":"35-46","gmt_create":"2026-05-23T15:23:21.571357+08:00","gmt_modified":"2026-05-23T15:23:21.571358+08:00"},{"id":"89c74d1f6c264e3b6b0232f7c2385cc7","path":"backend/app/workers/scheduler.py","line_range":"30-40","gmt_create":"2026-05-23T15:23:21.592339+08:00","gmt_modified":"2026-05-23T15:23:21.59234+08:00"},{"id":"d51485da00706b78a1bc7eb4290c8044","path":"backend/app/agent_framework/dispatcher.py","line_range":"118-154","gmt_create":"2026-05-23T15:23:21.594039+08:00","gmt_modified":"2026-05-23T15:23:21.59404+08:00"},{"id":"041b88dd888e1118b1b0be80f9ec4904","path":"backend/app/agent_framework/base.py","line_range":"1-223","gmt_create":"2026-05-23T15:24:01.695238+08:00","gmt_modified":"2026-05-23T15:24:01.695238+08:00"},{"id":"aba7dcba1181acae0e810fe447807010","path":"backend/app/agent_framework/registry.py","line_range":"1-219","gmt_create":"2026-05-23T15:24:01.696671+08:00","gmt_modified":"2026-05-23T15:24:01.696671+08:00"},{"id":"4a0f6c5332f954161992df9247e63a97","path":"backend/app/workers/llm_adapter.py","line_range":"1-281","gmt_create":"2026-05-23T15:24:01.701215+08:00","gmt_modified":"2026-05-23T15:24:01.701216+08:00"},{"id":"d432677dc357ec0518cc70701962e6bd","path":"backend/pipelines/content_production.yaml","line_range":"1-65","gmt_create":"2026-05-23T15:24:01.702282+08:00","gmt_modified":"2026-05-23T15:24:01.702283+08:00"},{"id":"3d50a008bc36ea9fed48168c2597933d","path":"backend/pipelines/diagnosis.yaml","line_range":"1-30","gmt_create":"2026-05-23T15:24:01.703321+08:00","gmt_modified":"2026-05-23T15:24:01.703321+08:00"},{"id":"bf0d60f20f3ea5a2f2458ba86d3f9173","path":"backend/app/models/agent.py","line_range":"1-206","gmt_create":"2026-05-23T15:24:01.784724+08:00","gmt_modified":"2026-05-23T15:24:01.784725+08:00"},{"id":"81d750ebce1c6f458a3499de79002778","path":"backend/app/agent_framework/base.py","line_range":"52-114","gmt_create":"2026-05-23T15:24:01.786275+08:00","gmt_modified":"2026-05-23T15:24:01.786276+08:00"},{"id":"07fd98ac292cc72700ce97168ed58d9a","path":"backend/app/agent_framework/base.py","line_range":"148-182","gmt_create":"2026-05-23T15:24:01.789406+08:00","gmt_modified":"2026-05-23T15:24:01.789406+08:00"},{"id":"ff27531ef3cacd097bc66aa7e982158d","path":"backend/app/agent_framework/registry.py","line_range":"29-80","gmt_create":"2026-05-23T15:24:01.791256+08:00","gmt_modified":"2026-05-23T15:24:01.791256+08:00"},{"id":"27a49e5089cfba7405dc53418c54dd37","path":"backend/app/agent_framework/registry.py","line_range":"156-172","gmt_create":"2026-05-23T15:24:01.792132+08:00","gmt_modified":"2026-05-23T15:24:01.792133+08:00"},{"id":"c0d940dbb4ac9ef819aad6c16edc0d60","path":"backend/app/agent_framework/registry.py","line_range":"174-201","gmt_create":"2026-05-23T15:24:01.79304+08:00","gmt_modified":"2026-05-23T15:24:01.79304+08:00"},{"id":"7a66c4fd8249f7d534ebe9092faa1124","path":"backend/app/agent_framework/dispatcher.py","line_range":"169-218","gmt_create":"2026-05-23T15:24:01.794779+08:00","gmt_modified":"2026-05-23T15:24:01.794779+08:00"},{"id":"962888e682bf9d3ceaa4d5bd5e75bb2c","path":"backend/app/services/llm/factory.py","line_range":"25-50","gmt_create":"2026-05-23T15:24:01.800754+08:00","gmt_modified":"2026-05-23T15:24:01.800755+08:00"},{"id":"ea929f7dbed5834bb5b3e24ebb32a0bc","path":"backend/app/workers/llm_adapter.py","line_range":"71-110","gmt_create":"2026-05-23T15:24:01.801726+08:00","gmt_modified":"2026-05-23T15:24:01.801727+08:00"},{"id":"ef16244eb1b5c1ab8774199c05bf0151","path":"backend/app/workers/llm_adapter.py","line_range":"220-270","gmt_create":"2026-05-23T15:24:01.803485+08:00","gmt_modified":"2026-05-23T15:24:01.803486+08:00"},{"id":"678dbba75fa1ffc2d9230f9e3ef7cc6f","path":"backend/app/agent_framework/agents/content_generator_agent.py","line_range":"111-182","gmt_create":"2026-05-23T15:24:01.806876+08:00","gmt_modified":"2026-05-23T15:24:01.806876+08:00"},{"id":"c32c02777f644d164c73710bcdd9c25c","path":"backend/app/agent_framework/agents/content_generator_agent.py","line_range":"184-252","gmt_create":"2026-05-23T15:24:01.807789+08:00","gmt_modified":"2026-05-23T15:24:01.80779+08:00"},{"id":"860a2f84ff90988124545bb7386f7e45","path":"backend/app/agent_framework/agents/geo_optimizer_agent.py","line_range":"104-180","gmt_create":"2026-05-23T15:24:01.808664+08:00","gmt_modified":"2026-05-23T15:24:01.808664+08:00"},{"id":"ccbe69d125e99e73a7907f2c94c59cc3","path":"backend/pipelines/content_production.yaml","line_range":"9-65","gmt_create":"2026-05-23T15:24:01.811957+08:00","gmt_modified":"2026-05-23T15:24:01.811958+08:00"},{"id":"63b5e7a6a9a5545b70747bcbcae293f9","path":"backend/pipelines/diagnosis.yaml","line_range":"8-30","gmt_create":"2026-05-23T15:24:01.814726+08:00","gmt_modified":"2026-05-23T15:24:01.814726+08:00"},{"id":"cdcf6ce33785e1c04e59e8244ca38ec8","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"256-327","gmt_create":"2026-05-23T15:24:01.817005+08:00","gmt_modified":"2026-05-23T15:24:01.817006+08:00"},{"id":"8d044a978198d9cd54d1b3d8e41194c0","path":"backend/app/agent_framework/pipeline/schema.py","line_range":"1-102","gmt_create":"2026-05-23T15:24:01.820305+08:00","gmt_modified":"2026-05-23T15:24:01.820305+08:00"},{"id":"960edc307c80a05c1d234e641a795b35","path":"backend/app/workers/llm_adapter.py","line_range":"141-218","gmt_create":"2026-05-23T15:24:01.888133+08:00","gmt_modified":"2026-05-23T15:24:01.888133+08:00"},{"id":"8bf01ba5b11502e9f6f9802c9735f370","path":"backend/app/agent_framework/pipeline/loader.py","line_range":"124-134","gmt_create":"2026-05-23T15:24:01.889218+08:00","gmt_modified":"2026-05-23T15:24:01.889219+08:00"},{"id":"70985e6be46865e7b0a26fdaab7ce0d2","path":"frontend/lib/api.ts","line_range":"1-58","gmt_create":"2026-05-23T15:26:09.829344+08:00","gmt_modified":"2026-05-23T15:26:09.829344+08:00"},{"id":"42315d289241195bda33f7251dff0396","path":"frontend/lib/api/agents.ts","line_range":"1-57","gmt_create":"2026-05-23T15:26:09.830427+08:00","gmt_modified":"2026-05-23T15:26:09.830427+08:00"},{"id":"370e7d15bc2a240ba54af22c704f8192","path":"backend/app/agent_framework/config_manager.py","line_range":"1-191","gmt_create":"2026-05-23T15:26:09.842759+08:00","gmt_modified":"2026-05-23T15:26:09.842759+08:00"},{"id":"db3ad017a4a81f38a1e6008d01fb07fb","path":"backend/app/agent_framework/pipeline/engine.py","line_range":"1-376","gmt_create":"2026-05-23T15:26:09.844277+08:00","gmt_modified":"2026-05-23T15:26:09.844277+08:00"},{"id":"41c1962c6c680f23f0fde4efc0edc618","path":"backend/app/api/agents.py","line_range":"1-299","gmt_create":"2026-05-23T15:26:09.848268+08:00","gmt_modified":"2026-05-23T15:26:09.848268+08:00"},{"id":"08d06b8b6e8c01974ec66e0a5b10795f","path":"backend/app/schemas/query.py","line_range":"6-8","gmt_create":"2026-05-23T15:26:09.909298+08:00","gmt_modified":"2026-05-23T15:26:09.909298+08:00"},{"id":"a6811a3e7a5e0874867a1839912ac150","path":"frontend/lib/api.ts","line_range":"1","gmt_create":"2026-05-23T15:26:09.911586+08:00","gmt_modified":"2026-05-23T15:26:09.911586+08:00"},{"id":"7480204ff8e76e1fedc3c82967acbddf","path":".env.example","line_range":"1-35","gmt_create":"2026-05-23T15:26:09.913415+08:00","gmt_modified":"2026-05-23T15:26:09.913415+08:00"},{"id":"b41c589b6a7e0c0addb0aa1d78666cf7","path":"backend/app/schemas/query.py","line_range":"6","gmt_create":"2026-05-23T15:26:09.925138+08:00","gmt_modified":"2026-05-23T15:26:09.925138+08:00"},{"id":"05089063cd933e72db9ddd32806194bb","path":"backend/requirements.txt","line_range":"5-8","gmt_create":"2026-05-23T15:26:09.926939+08:00","gmt_modified":"2026-05-23T15:26:09.92694+08:00"},{"id":"0a7f1ad960e7961b21073bdd1dbef2cb","path":"frontend/lib/api.ts","line_range":"3-21","gmt_create":"2026-05-23T15:26:09.928426+08:00","gmt_modified":"2026-05-23T15:26:09.928426+08:00"},{"id":"c099b506f31f17751b7e08f64b2b1cbe","path":"frontend/lib/api.ts","line_range":"16-21","gmt_create":"2026-05-23T15:26:09.941061+08:00","gmt_modified":"2026-05-23T15:26:09.941062+08:00"},{"id":"6997483bdbba1455b9454fe4cccbba45","path":"backend/app/workers/platforms/kimi.py","line_range":"23-32","gmt_create":"2026-05-23T15:26:09.953513+08:00","gmt_modified":"2026-05-23T15:26:09.953513+08:00"}],"knowledge_relations":[{"id":48,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-23T15:19:43.777831+08:00","gmt_modified":"2026-04-23T15:19:43.777831+08:00"},{"id":49,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-04-23T15:19:43.778774+08:00","gmt_modified":"2026-04-23T15:19:43.778774+08:00"},{"id":50,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"eca13a610badfc5ffc6210827fb96991","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/header.tsx","gmt_create":"2026-04-23T15:19:43.779153+08:00","gmt_modified":"2026-04-23T15:19:43.779154+08:00"},{"id":51,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"18a0651d895fba9bb4e0c0229459efdc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/sidebar.tsx","gmt_create":"2026-04-23T15:19:43.779524+08:00","gmt_modified":"2026-04-23T15:19:43.779524+08:00"},{"id":52,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-23T15:19:43.779869+08:00","gmt_modified":"2026-04-23T15:19:43.779869+08:00"},{"id":53,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/table.tsx","gmt_create":"2026-04-23T15:19:43.780775+08:00","gmt_modified":"2026-04-23T15:19:43.780775+08:00"},{"id":54,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"108b0c4b4dcfb6aa39a5eb138225c148","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dialog.tsx","gmt_create":"2026-04-23T15:19:43.781767+08:00","gmt_modified":"2026-04-23T15:19:43.781767+08:00"},{"id":55,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T15:19:43.782177+08:00","gmt_modified":"2026-04-23T15:19:43.782177+08:00"},{"id":56,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"f93ae024fe0a2e69698037dff6df205f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/utils.ts","gmt_create":"2026-04-23T15:19:43.782527+08:00","gmt_modified":"2026-04-23T15:19:43.782527+08:00"},{"id":57,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"d5f2266643d2011c66e86af088ec637f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/trend-chart.tsx","gmt_create":"2026-04-23T15:19:43.782861+08:00","gmt_modified":"2026-04-23T15:19:43.782861+08:00"},{"id":58,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"f1a7d61831cc0a45ac6220294f15c21d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-23T15:19:43.783164+08:00","gmt_modified":"2026-04-23T15:19:43.783165+08:00"},{"id":59,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-23T15:19:43.783668+08:00","gmt_modified":"2026-04-23T15:19:43.783668+08:00"},{"id":60,"source_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T15:19:43.783987+08:00","gmt_modified":"2026-04-23T15:19:43.783987+08:00"},{"id":61,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3bd4eedea376e3a3d9f9fbff4fe27a65","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/sidebar.tsx#1-54","gmt_create":"2026-04-23T15:19:43.784455+08:00","gmt_modified":"2026-04-23T15:19:43.784455+08:00"},{"id":62,"source_id":"18a0651d895fba9bb4e0c0229459efdc","target_id":"3bd4eedea376e3a3d9f9fbff4fe27a65","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-54","gmt_create":"2026-04-23T15:19:43.784807+08:00","gmt_modified":"2026-04-23T15:19:43.784807+08:00"},{"id":63,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/header.tsx#1-30","gmt_create":"2026-04-23T15:19:43.785303+08:00","gmt_modified":"2026-04-23T15:19:43.785303+08:00"},{"id":64,"source_id":"eca13a610badfc5ffc6210827fb96991","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-30","gmt_create":"2026-04-23T15:19:43.785622+08:00","gmt_modified":"2026-04-23T15:19:43.785622+08:00"},{"id":65,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#1-118","gmt_create":"2026-04-23T15:19:43.78727+08:00","gmt_modified":"2026-04-23T15:19:43.787271+08:00"},{"id":66,"source_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-118","gmt_create":"2026-04-23T15:19:43.788224+08:00","gmt_modified":"2026-04-23T15:19:43.788224+08:00"},{"id":67,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#1-123","gmt_create":"2026-04-23T15:19:43.789533+08:00","gmt_modified":"2026-04-23T15:19:43.789533+08:00"},{"id":68,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:19:43.790255+08:00","gmt_modified":"2026-04-23T15:19:43.790255+08:00"},{"id":69,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"b7796fc6197ecce5beb461b9466e54a0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/trend-chart.tsx#1-60","gmt_create":"2026-04-23T15:19:43.790795+08:00","gmt_modified":"2026-04-23T15:19:43.790795+08:00"},{"id":70,"source_id":"d5f2266643d2011c66e86af088ec637f","target_id":"b7796fc6197ecce5beb461b9466e54a0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-60","gmt_create":"2026-04-23T15:19:43.791134+08:00","gmt_modified":"2026-04-23T15:19:43.791134+08:00"},{"id":71,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/platform-chart.tsx#1-68","gmt_create":"2026-04-23T15:19:43.791601+08:00","gmt_modified":"2026-04-23T15:19:43.791601+08:00"},{"id":72,"source_id":"f1a7d61831cc0a45ac6220294f15c21d","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-68","gmt_create":"2026-04-23T15:19:43.791902+08:00","gmt_modified":"2026-04-23T15:19:43.791902+08:00"},{"id":73,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-18","gmt_create":"2026-04-23T15:19:43.792356+08:00","gmt_modified":"2026-04-23T15:19:43.792356+08:00"},{"id":74,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-18","gmt_create":"2026-04-23T15:19:43.79267+08:00","gmt_modified":"2026-04-23T15:19:43.79267+08:00"},{"id":75,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#1-7","gmt_create":"2026-04-23T15:19:43.79312+08:00","gmt_modified":"2026-04-23T15:19:43.79312+08:00"},{"id":76,"source_id":"f93ae024fe0a2e69698037dff6df205f","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-7","gmt_create":"2026-04-23T15:19:43.793455+08:00","gmt_modified":"2026-04-23T15:19:43.793455+08:00"},{"id":77,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"0f87c8089f548883d056f0a0d79e273f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-79","gmt_create":"2026-04-23T15:19:43.793866+08:00","gmt_modified":"2026-04-23T15:19:43.793866+08:00"},{"id":78,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"0f87c8089f548883d056f0a0d79e273f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-79","gmt_create":"2026-04-23T15:19:43.794158+08:00","gmt_modified":"2026-04-23T15:19:43.794158+08:00"},{"id":79,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"9beee1f41fe8f0750fd97155f9d54bbb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#67-70","gmt_create":"2026-04-23T15:19:43.797877+08:00","gmt_modified":"2026-04-23T15:19:43.797877+08:00"},{"id":80,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"9beee1f41fe8f0750fd97155f9d54bbb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-70","gmt_create":"2026-04-23T15:19:43.798244+08:00","gmt_modified":"2026-04-23T15:19:43.798244+08:00"},{"id":81,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"8fe2e22a963442076e1ce16ab777573c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#56-66","gmt_create":"2026-04-23T15:19:43.799319+08:00","gmt_modified":"2026-04-23T15:19:43.799319+08:00"},{"id":82,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"8fe2e22a963442076e1ce16ab777573c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-66","gmt_create":"2026-04-23T15:19:43.799625+08:00","gmt_modified":"2026-04-23T15:19:43.799625+08:00"},{"id":83,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"3124ad882ca2cf8fecb6b93696c7f233","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#72-77","gmt_create":"2026-04-23T15:19:43.801555+08:00","gmt_modified":"2026-04-23T15:19:43.801555+08:00"},{"id":84,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"3124ad882ca2cf8fecb6b93696c7f233","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-77","gmt_create":"2026-04-23T15:19:43.801939+08:00","gmt_modified":"2026-04-23T15:19:43.801939+08:00"},{"id":85,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"17a97b4ac37fb67b8eda7ce2887c38e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#17-20","gmt_create":"2026-04-23T15:19:43.806186+08:00","gmt_modified":"2026-04-23T15:19:43.806186+08:00"},{"id":86,"source_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","target_id":"17a97b4ac37fb67b8eda7ce2887c38e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-20","gmt_create":"2026-04-23T15:19:43.80664+08:00","gmt_modified":"2026-04-23T15:19:43.80664+08:00"},{"id":87,"source_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","target_id":"84cba1e0d516e8c9859402fd5c1bc83c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#3-40","gmt_create":"2026-04-23T15:19:43.815637+08:00","gmt_modified":"2026-04-23T15:19:43.815637+08:00"},{"id":88,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"84cba1e0d516e8c9859402fd5c1bc83c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-40","gmt_create":"2026-04-23T15:19:43.817147+08:00","gmt_modified":"2026-04-23T15:19:43.817147+08:00"},{"id":107,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"b55a164add5a8fec2ef0e489f7234829","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-47","gmt_create":"2026-04-23T15:19:45.617445+08:00","gmt_modified":"2026-04-23T15:19:45.617445+08:00"},{"id":109,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"16d619435094a63740357cd6317b52cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10","gmt_create":"2026-04-23T15:19:45.618177+08:00","gmt_modified":"2026-04-23T15:19:45.618177+08:00"},{"id":111,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"fa1ee5e3822128a37e9d03af74083392","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12","gmt_create":"2026-04-23T15:19:45.619215+08:00","gmt_modified":"2026-04-23T15:19:45.619215+08:00"},{"id":113,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"7e908f05baccdfcf7f4a3ef3c9cd5c38","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21","gmt_create":"2026-04-23T15:19:45.620246+08:00","gmt_modified":"2026-04-23T15:19:45.620246+08:00"},{"id":115,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"ffe6df344be81bde3941ad8f0d77910b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13","gmt_create":"2026-04-23T15:19:45.623067+08:00","gmt_modified":"2026-04-23T15:19:45.623067+08:00"},{"id":117,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"c71fb14f8866e34c679c94a4e2432bc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13","gmt_create":"2026-04-23T15:19:45.624846+08:00","gmt_modified":"2026-04-23T15:19:45.624846+08:00"},{"id":119,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"3c68f1581d2fd6aa845dd71111a9aa9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:19:45.625985+08:00","gmt_modified":"2026-04-23T15:19:45.625985+08:00"},{"id":121,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"39afb05755a93800fd685af7274110cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-57","gmt_create":"2026-04-23T15:19:45.626917+08:00","gmt_modified":"2026-04-23T15:19:45.626917+08:00"},{"id":123,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"87a177f17800991e1ed1fb7be03abdb2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-42","gmt_create":"2026-04-23T15:19:45.627772+08:00","gmt_modified":"2026-04-23T15:19:45.627772+08:00"},{"id":125,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"ae9de874df4a46f4197b6c157c25ec6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-85","gmt_create":"2026-04-23T15:19:45.628538+08:00","gmt_modified":"2026-04-23T15:19:45.628538+08:00"},{"id":127,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-77","gmt_create":"2026-04-23T15:19:45.629465+08:00","gmt_modified":"2026-04-23T15:19:45.629465+08:00"},{"id":129,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"177c73dc4e71186d9eaa1157fc0fe97f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-46","gmt_create":"2026-04-23T15:19:45.630333+08:00","gmt_modified":"2026-04-23T15:19:45.630333+08:00"},{"id":131,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"a0be0cbddb559575861620b5b7579634","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-51","gmt_create":"2026-04-23T15:19:45.631178+08:00","gmt_modified":"2026-04-23T15:19:45.631178+08:00"},{"id":133,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"bcdf50f6234651cb9863ab210e6473e5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-42","gmt_create":"2026-04-23T15:19:45.632177+08:00","gmt_modified":"2026-04-23T15:19:45.632177+08:00"},{"id":135,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"6df0277c2486b148fa26c2682dbdaa4c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-68","gmt_create":"2026-04-23T15:19:45.63307+08:00","gmt_modified":"2026-04-23T15:19:45.63307+08:00"},{"id":137,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"5ea5f192d580031ffe57e1582b70c67e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-123","gmt_create":"2026-04-23T15:19:45.633929+08:00","gmt_modified":"2026-04-23T15:19:45.633929+08:00"},{"id":139,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"fe4a793f16cd4e12b56253c0a6d53ae0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-359","gmt_create":"2026-04-23T15:19:45.634775+08:00","gmt_modified":"2026-04-23T15:19:45.634775+08:00"},{"id":141,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"9552bd8a528207f18e4f3a1696f26a55","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-37","gmt_create":"2026-04-23T15:19:45.635763+08:00","gmt_modified":"2026-04-23T15:19:45.635763+08:00"},{"id":143,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-34","gmt_create":"2026-04-23T15:19:45.639659+08:00","gmt_modified":"2026-04-23T15:19:45.63966+08:00"},{"id":145,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-81","gmt_create":"2026-04-23T15:19:45.641965+08:00","gmt_modified":"2026-04-23T15:19:45.641965+08:00"},{"id":147,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"69118807690ef351a9de910414d5e676","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-94","gmt_create":"2026-04-23T15:19:45.643362+08:00","gmt_modified":"2026-04-23T15:19:45.643362+08:00"},{"id":149,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-77","gmt_create":"2026-04-23T15:19:45.644457+08:00","gmt_modified":"2026-04-23T15:19:45.644457+08:00"},{"id":151,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"b0777c7da17be89abb333c81c0dcf349","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 204-261","gmt_create":"2026-04-23T15:19:45.645243+08:00","gmt_modified":"2026-04-23T15:19:45.645243+08:00"},{"id":153,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-50","gmt_create":"2026-04-23T15:19:45.646445+08:00","gmt_modified":"2026-04-23T15:19:45.646445+08:00"},{"id":155,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dbf5f8a57778cf6363e834081f3d771c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 327-359","gmt_create":"2026-04-23T15:19:45.647935+08:00","gmt_modified":"2026-04-23T15:19:45.647935+08:00"},{"id":157,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-41","gmt_create":"2026-04-23T15:19:45.649807+08:00","gmt_modified":"2026-04-23T15:19:45.649807+08:00"},{"id":159,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-55","gmt_create":"2026-04-23T15:19:45.650642+08:00","gmt_modified":"2026-04-23T15:19:45.650642+08:00"},{"id":161,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-42","gmt_create":"2026-04-23T15:19:45.651529+08:00","gmt_modified":"2026-04-23T15:19:45.651529+08:00"},{"id":163,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"b84f46f058847733347974841f613688","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-39","gmt_create":"2026-04-23T15:19:45.65251+08:00","gmt_modified":"2026-04-23T15:19:45.65251+08:00"},{"id":165,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"1a2657244414b5681afded9565a86422","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-40","gmt_create":"2026-04-23T15:19:45.655814+08:00","gmt_modified":"2026-04-23T15:19:45.655814+08:00"},{"id":167,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 43-48","gmt_create":"2026-04-23T15:19:45.657941+08:00","gmt_modified":"2026-04-23T15:19:45.657942+08:00"},{"id":169,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"27a5e2dd1d197b2e3a45be41c57a6183","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35","gmt_create":"2026-04-23T15:19:45.658966+08:00","gmt_modified":"2026-04-23T15:19:45.658966+08:00"},{"id":171,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"c43e8fc0c04c5ed2db7798d99c8c77b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34","gmt_create":"2026-04-23T15:19:45.659763+08:00","gmt_modified":"2026-04-23T15:19:45.659763+08:00"},{"id":173,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"8868ab86034eecf40e80347ef8cbdebd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-30","gmt_create":"2026-04-23T15:19:45.660491+08:00","gmt_modified":"2026-04-23T15:19:45.660491+08:00"},{"id":175,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"a50f983ec39bac67dff5df80f6dad837","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-60","gmt_create":"2026-04-23T15:19:45.661271+08:00","gmt_modified":"2026-04-23T15:19:45.661271+08:00"},{"id":177,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-71","gmt_create":"2026-04-23T15:19:45.662055+08:00","gmt_modified":"2026-04-23T15:19:45.662055+08:00"},{"id":179,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"6ef6d32f97d7b50b7a4da541137423c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-27","gmt_create":"2026-04-23T15:19:45.662999+08:00","gmt_modified":"2026-04-23T15:19:45.662999+08:00"},{"id":180,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T15:20:08.989793+08:00","gmt_modified":"2026-04-23T15:20:08.989793+08:00"},{"id":181,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T15:20:08.990186+08:00","gmt_modified":"2026-04-23T15:20:08.990186+08:00"},{"id":182,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T15:20:08.990539+08:00","gmt_modified":"2026-04-23T15:20:08.990539+08:00"},{"id":183,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T15:20:08.990851+08:00","gmt_modified":"2026-04-23T15:20:08.990851+08:00"},{"id":184,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T15:20:08.991166+08:00","gmt_modified":"2026-04-23T15:20:08.991166+08:00"},{"id":185,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T15:20:08.991471+08:00","gmt_modified":"2026-04-23T15:20:08.991472+08:00"},{"id":186,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T15:20:08.991772+08:00","gmt_modified":"2026-04-23T15:20:08.991772+08:00"},{"id":187,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T15:20:08.992186+08:00","gmt_modified":"2026-04-23T15:20:08.992186+08:00"},{"id":188,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T15:20:08.992542+08:00","gmt_modified":"2026-04-23T15:20:08.992542+08:00"},{"id":189,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T15:20:08.992879+08:00","gmt_modified":"2026-04-23T15:20:08.992879+08:00"},{"id":190,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T15:20:08.997487+08:00","gmt_modified":"2026-04-23T15:20:08.997487+08:00"},{"id":191,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T15:20:08.998695+08:00","gmt_modified":"2026-04-23T15:20:08.998696+08:00"},{"id":192,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T15:20:08.999402+08:00","gmt_modified":"2026-04-23T15:20:08.999402+08:00"},{"id":193,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-04-23T15:20:09.000067+08:00","gmt_modified":"2026-04-23T15:20:09.000067+08:00"},{"id":194,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-04-23T15:20:09.000413+08:00","gmt_modified":"2026-04-23T15:20:09.000413+08:00"},{"id":195,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T15:20:09.000893+08:00","gmt_modified":"2026-04-23T15:20:09.000893+08:00"},{"id":196,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-22","gmt_create":"2026-04-23T15:20:09.00176+08:00","gmt_modified":"2026-04-23T15:20:09.00176+08:00"},{"id":197,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T15:20:09.003004+08:00","gmt_modified":"2026-04-23T15:20:09.003004+08:00"},{"id":198,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-95","gmt_create":"2026-04-23T15:20:09.003771+08:00","gmt_modified":"2026-04-23T15:20:09.003771+08:00"},{"id":199,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T15:20:09.005186+08:00","gmt_modified":"2026-04-23T15:20:09.005186+08:00"},{"id":200,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-309","gmt_create":"2026-04-23T15:20:09.00622+08:00","gmt_modified":"2026-04-23T15:20:09.00622+08:00"},{"id":201,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T15:20:09.006997+08:00","gmt_modified":"2026-04-23T15:20:09.006997+08:00"},{"id":202,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T15:20:09.007995+08:00","gmt_modified":"2026-04-23T15:20:09.007995+08:00"},{"id":203,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T15:20:09.009222+08:00","gmt_modified":"2026-04-23T15:20:09.009222+08:00"},{"id":204,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T15:20:09.010245+08:00","gmt_modified":"2026-04-23T15:20:09.010245+08:00"},{"id":205,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-130","gmt_create":"2026-04-23T15:20:09.011044+08:00","gmt_modified":"2026-04-23T15:20:09.011044+08:00"},{"id":206,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T15:20:09.012195+08:00","gmt_modified":"2026-04-23T15:20:09.012195+08:00"},{"id":207,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-04-23T15:20:09.01291+08:00","gmt_modified":"2026-04-23T15:20:09.012911+08:00"},{"id":208,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T15:20:09.013886+08:00","gmt_modified":"2026-04-23T15:20:09.013886+08:00"},{"id":209,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-18","gmt_create":"2026-04-23T15:20:09.014746+08:00","gmt_modified":"2026-04-23T15:20:09.014746+08:00"},{"id":210,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T15:20:09.015594+08:00","gmt_modified":"2026-04-23T15:20:09.015594+08:00"},{"id":211,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-206","gmt_create":"2026-04-23T15:20:09.016313+08:00","gmt_modified":"2026-04-23T15:20:09.016313+08:00"},{"id":212,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T15:20:09.017693+08:00","gmt_modified":"2026-04-23T15:20:09.017693+08:00"},{"id":213,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-205","gmt_create":"2026-04-23T15:20:09.018896+08:00","gmt_modified":"2026-04-23T15:20:09.018896+08:00"},{"id":214,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#30-90","gmt_create":"2026-04-23T15:20:09.025147+08:00","gmt_modified":"2026-04-23T15:20:09.025147+08:00"},{"id":215,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-90","gmt_create":"2026-04-23T15:20:09.02579+08:00","gmt_modified":"2026-04-23T15:20:09.02579+08:00"},{"id":216,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"91bda120c0ab69e0e7103a1c89c82424","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#95-172","gmt_create":"2026-04-23T15:20:09.026853+08:00","gmt_modified":"2026-04-23T15:20:09.026853+08:00"},{"id":217,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"91bda120c0ab69e0e7103a1c89c82424","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 95-172","gmt_create":"2026-04-23T15:20:09.027566+08:00","gmt_modified":"2026-04-23T15:20:09.027566+08:00"},{"id":218,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T15:20:09.028202+08:00","gmt_modified":"2026-04-23T15:20:09.028202+08:00"},{"id":219,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 159-234","gmt_create":"2026-04-23T15:20:09.028744+08:00","gmt_modified":"2026-04-23T15:20:09.028744+08:00"},{"id":220,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"6712051c987e10a7c26b089063367398","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#24-31","gmt_create":"2026-04-23T15:20:09.029494+08:00","gmt_modified":"2026-04-23T15:20:09.029494+08:00"},{"id":221,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"6712051c987e10a7c26b089063367398","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-31","gmt_create":"2026-04-23T15:20:09.030084+08:00","gmt_modified":"2026-04-23T15:20:09.030084+08:00"},{"id":222,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#24-32","gmt_create":"2026-04-23T15:20:09.030828+08:00","gmt_modified":"2026-04-23T15:20:09.030828+08:00"},{"id":223,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-32","gmt_create":"2026-04-23T15:20:09.031632+08:00","gmt_modified":"2026-04-23T15:20:09.031632+08:00"},{"id":224,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"06ed912983db33bb8aca162fed68282b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#24-29","gmt_create":"2026-04-23T15:20:09.032417+08:00","gmt_modified":"2026-04-23T15:20:09.032417+08:00"},{"id":225,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"06ed912983db33bb8aca162fed68282b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-29","gmt_create":"2026-04-23T15:20:09.032976+08:00","gmt_modified":"2026-04-23T15:20:09.032976+08:00"},{"id":226,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-120","gmt_create":"2026-04-23T15:20:09.037331+08:00","gmt_modified":"2026-04-23T15:20:09.037331+08:00"},{"id":227,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-120","gmt_create":"2026-04-23T15:20:09.038413+08:00","gmt_modified":"2026-04-23T15:20:09.038413+08:00"},{"id":228,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"40d0b169aad65c8bb38077deb052fc72","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-125","gmt_create":"2026-04-23T15:20:09.040261+08:00","gmt_modified":"2026-04-23T15:20:09.040261+08:00"},{"id":229,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"40d0b169aad65c8bb38077deb052fc72","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-125","gmt_create":"2026-04-23T15:20:09.04098+08:00","gmt_modified":"2026-04-23T15:20:09.04098+08:00"},{"id":230,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"8b5af998852596e1e08b0e0216bc4b93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-124","gmt_create":"2026-04-23T15:20:09.041526+08:00","gmt_modified":"2026-04-23T15:20:09.041526+08:00"},{"id":231,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"8b5af998852596e1e08b0e0216bc4b93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-124","gmt_create":"2026-04-23T15:20:09.041834+08:00","gmt_modified":"2026-04-23T15:20:09.041834+08:00"},{"id":232,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T15:20:09.04598+08:00","gmt_modified":"2026-04-23T15:20:09.04598+08:00"},{"id":233,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-86","gmt_create":"2026-04-23T15:20:09.046352+08:00","gmt_modified":"2026-04-23T15:20:09.046352+08:00"},{"id":234,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#42-90","gmt_create":"2026-04-23T15:20:09.050041+08:00","gmt_modified":"2026-04-23T15:20:09.050041+08:00"},{"id":235,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-90","gmt_create":"2026-04-23T15:20:09.050351+08:00","gmt_modified":"2026-04-23T15:20:09.050351+08:00"},{"id":236,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e79301a4bc26aa6b49f3f52c3182c3f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#175-234","gmt_create":"2026-04-23T15:20:09.051815+08:00","gmt_modified":"2026-04-23T15:20:09.051815+08:00"},{"id":237,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"e79301a4bc26aa6b49f3f52c3182c3f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 175-234","gmt_create":"2026-04-23T15:20:09.052165+08:00","gmt_modified":"2026-04-23T15:20:09.052166+08:00"},{"id":238,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-48","gmt_create":"2026-04-23T15:20:09.052615+08:00","gmt_modified":"2026-04-23T15:20:09.052615+08:00"},{"id":239,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-48","gmt_create":"2026-04-23T15:20:09.052947+08:00","gmt_modified":"2026-04-23T15:20:09.052947+08:00"},{"id":240,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-48","gmt_create":"2026-04-23T15:20:09.053449+08:00","gmt_modified":"2026-04-23T15:20:09.053449+08:00"},{"id":241,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-48","gmt_create":"2026-04-23T15:20:09.053892+08:00","gmt_modified":"2026-04-23T15:20:09.053892+08:00"},{"id":242,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"e4a49039dae40b7433896c81737fcf8c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-14","gmt_create":"2026-04-23T15:20:09.05437+08:00","gmt_modified":"2026-04-23T15:20:09.05437+08:00"},{"id":243,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"e4a49039dae40b7433896c81737fcf8c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-14","gmt_create":"2026-04-23T15:20:09.054841+08:00","gmt_modified":"2026-04-23T15:20:09.054841+08:00"},{"id":244,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2ee31d68c409e96e951f6cfa7027bca7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-42","gmt_create":"2026-04-23T15:20:09.055328+08:00","gmt_modified":"2026-04-23T15:20:09.055328+08:00"},{"id":245,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"2ee31d68c409e96e951f6cfa7027bca7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-42","gmt_create":"2026-04-23T15:20:09.055781+08:00","gmt_modified":"2026-04-23T15:20:09.055781+08:00"},{"id":246,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"79d6e169e36e6b7493898b5f863e07dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#152-157","gmt_create":"2026-04-23T15:20:09.056898+08:00","gmt_modified":"2026-04-23T15:20:09.056898+08:00"},{"id":247,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"79d6e169e36e6b7493898b5f863e07dc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 152-157","gmt_create":"2026-04-23T15:20:09.057188+08:00","gmt_modified":"2026-04-23T15:20:09.057188+08:00"},{"id":248,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"1552315d5fb9f6d7aba5f7e8fa93a975","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-10","gmt_create":"2026-04-23T15:20:09.058217+08:00","gmt_modified":"2026-04-23T15:20:09.058217+08:00"},{"id":249,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"1552315d5fb9f6d7aba5f7e8fa93a975","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-10","gmt_create":"2026-04-23T15:20:09.058503+08:00","gmt_modified":"2026-04-23T15:20:09.058503+08:00"},{"id":250,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"599cca7536cae4a7e0ae93043c476a7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#10-154","gmt_create":"2026-04-23T15:20:09.058947+08:00","gmt_modified":"2026-04-23T15:20:09.058947+08:00"},{"id":251,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"599cca7536cae4a7e0ae93043c476a7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-154","gmt_create":"2026-04-23T15:20:09.059242+08:00","gmt_modified":"2026-04-23T15:20:09.059242+08:00"},{"id":252,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2ec3d45edd6221e0cedf7f8887fe090d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_scheduler.py#17-123","gmt_create":"2026-04-23T15:20:09.059776+08:00","gmt_modified":"2026-04-23T15:20:09.059776+08:00"},{"id":253,"source_id":"b2f0d46a31a5441594f2e777365fc156","target_id":"2ec3d45edd6221e0cedf7f8887fe090d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-123","gmt_create":"2026-04-23T15:20:09.060064+08:00","gmt_modified":"2026-04-23T15:20:09.060064+08:00"},{"id":254,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"99fe1b288fd41daa86c2dfbab819abf0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/__init__.py","gmt_create":"2026-04-23T15:21:46.707277+08:00","gmt_modified":"2026-04-23T15:21:46.707277+08:00"},{"id":255,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-23T15:21:46.707879+08:00","gmt_modified":"2026-04-23T15:21:46.707879+08:00"},{"id":256,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T15:21:46.708322+08:00","gmt_modified":"2026-04-23T15:21:46.708322+08:00"},{"id":257,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T15:21:46.708702+08:00","gmt_modified":"2026-04-23T15:21:46.708702+08:00"},{"id":258,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T15:21:46.709093+08:00","gmt_modified":"2026-04-23T15:21:46.709093+08:00"},{"id":259,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-04-23T15:21:46.709712+08:00","gmt_modified":"2026-04-23T15:21:46.709713+08:00"},{"id":260,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T15:21:46.710101+08:00","gmt_modified":"2026-04-23T15:21:46.710101+08:00"},{"id":261,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-23T15:21:46.710429+08:00","gmt_modified":"2026-04-23T15:21:46.710429+08:00"},{"id":262,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-04-23T15:21:46.710829+08:00","gmt_modified":"2026-04-23T15:21:46.710829+08:00"},{"id":263,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-23T15:21:46.711181+08:00","gmt_modified":"2026-04-23T15:21:46.711181+08:00"},{"id":264,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T15:21:46.711568+08:00","gmt_modified":"2026-04-23T15:21:46.711568+08:00"},{"id":265,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T15:21:46.711965+08:00","gmt_modified":"2026-04-23T15:21:46.711965+08:00"},{"id":266,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T15:21:46.712296+08:00","gmt_modified":"2026-04-23T15:21:46.712296+08:00"},{"id":267,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T15:21:46.712792+08:00","gmt_modified":"2026-04-23T15:21:46.712792+08:00"},{"id":268,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T15:21:46.713121+08:00","gmt_modified":"2026-04-23T15:21:46.713121+08:00"},{"id":269,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-23T15:21:46.713538+08:00","gmt_modified":"2026-04-23T15:21:46.713538+08:00"},{"id":270,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-23T15:21:46.71408+08:00","gmt_modified":"2026-04-23T15:21:46.71408+08:00"},{"id":271,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T15:21:46.714746+08:00","gmt_modified":"2026-04-23T15:21:46.714746+08:00"},{"id":272,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T15:21:46.715399+08:00","gmt_modified":"2026-04-23T15:21:46.7154+08:00"},{"id":273,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T15:21:46.716178+08:00","gmt_modified":"2026-04-23T15:21:46.716178+08:00"},{"id":274,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-04-23T15:21:46.717324+08:00","gmt_modified":"2026-04-23T15:21:46.717324+08:00"},{"id":275,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-37","gmt_create":"2026-04-23T15:21:46.718049+08:00","gmt_modified":"2026-04-23T15:21:46.71805+08:00"},{"id":276,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T15:21:46.718816+08:00","gmt_modified":"2026-04-23T15:21:46.718816+08:00"},{"id":277,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-123","gmt_create":"2026-04-23T15:21:46.719468+08:00","gmt_modified":"2026-04-23T15:21:46.719468+08:00"},{"id":278,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:21:46.720008+08:00","gmt_modified":"2026-04-23T15:21:46.720008+08:00"},{"id":279,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"121203f7f9f539ffb1456c3f5cdfd842","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-359","gmt_create":"2026-04-23T15:21:46.720615+08:00","gmt_modified":"2026-04-23T15:21:46.720615+08:00"},{"id":280,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"121203f7f9f539ffb1456c3f5cdfd842","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-359","gmt_create":"2026-04-23T15:21:46.721095+08:00","gmt_modified":"2026-04-23T15:21:46.721095+08:00"},{"id":281,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-23T15:21:46.721634+08:00","gmt_modified":"2026-04-23T15:21:46.721634+08:00"},{"id":282,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-86","gmt_create":"2026-04-23T15:21:46.722019+08:00","gmt_modified":"2026-04-23T15:21:46.722019+08:00"},{"id":283,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T15:21:46.722621+08:00","gmt_modified":"2026-04-23T15:21:46.722621+08:00"},{"id":284,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-78","gmt_create":"2026-04-23T15:21:46.723064+08:00","gmt_modified":"2026-04-23T15:21:46.723064+08:00"},{"id":285,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/__init__.py#1-14","gmt_create":"2026-04-23T15:21:46.72357+08:00","gmt_modified":"2026-04-23T15:21:46.72357+08:00"},{"id":286,"source_id":"99fe1b288fd41daa86c2dfbab819abf0","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-04-23T15:21:46.723873+08:00","gmt_modified":"2026-04-23T15:21:46.723873+08:00"},{"id":287,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#21-128","gmt_create":"2026-04-23T15:21:46.726415+08:00","gmt_modified":"2026-04-23T15:21:46.726416+08:00"},{"id":288,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-128","gmt_create":"2026-04-23T15:21:46.726829+08:00","gmt_modified":"2026-04-23T15:21:46.726829+08:00"},{"id":289,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"e454b4a54500bd81e7599e6ec97bf12b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#23-37","gmt_create":"2026-04-23T15:21:46.735019+08:00","gmt_modified":"2026-04-23T15:21:46.735019+08:00"},{"id":290,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"e454b4a54500bd81e7599e6ec97bf12b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-37","gmt_create":"2026-04-23T15:21:46.735734+08:00","gmt_modified":"2026-04-23T15:21:46.735734+08:00"},{"id":291,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1965adf7cfc65447e3c1ae21fbf6d1c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#39-59","gmt_create":"2026-04-23T15:21:46.737007+08:00","gmt_modified":"2026-04-23T15:21:46.737007+08:00"},{"id":292,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"1965adf7cfc65447e3c1ae21fbf6d1c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-59","gmt_create":"2026-04-23T15:21:46.744358+08:00","gmt_modified":"2026-04-23T15:21:46.744358+08:00"},{"id":293,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"c730faefb34bb87c40c5f636b4ff7f41","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#80-94","gmt_create":"2026-04-23T15:21:46.747533+08:00","gmt_modified":"2026-04-23T15:21:46.747534+08:00"},{"id":294,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"c730faefb34bb87c40c5f636b4ff7f41","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 80-94","gmt_create":"2026-04-23T15:21:46.748811+08:00","gmt_modified":"2026-04-23T15:21:46.748811+08:00"},{"id":295,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"b9978c3eccea3ef566b003216e5047af","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#61-78","gmt_create":"2026-04-23T15:21:46.751629+08:00","gmt_modified":"2026-04-23T15:21:46.751629+08:00"},{"id":296,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"b9978c3eccea3ef566b003216e5047af","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-78","gmt_create":"2026-04-23T15:21:46.752497+08:00","gmt_modified":"2026-04-23T15:21:46.752497+08:00"},{"id":297,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"eb6ff4361d7413b57f1f70b1ec2f0c94","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#96-111","gmt_create":"2026-04-23T15:21:46.753732+08:00","gmt_modified":"2026-04-23T15:21:46.753732+08:00"},{"id":298,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"eb6ff4361d7413b57f1f70b1ec2f0c94","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 96-111","gmt_create":"2026-04-23T15:21:46.754523+08:00","gmt_modified":"2026-04-23T15:21:46.754523+08:00"},{"id":299,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"1a2657244414b5681afded9565a86422","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#35-40","gmt_create":"2026-04-23T15:21:46.755683+08:00","gmt_modified":"2026-04-23T15:21:46.755683+08:00"},{"id":300,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#43-48","gmt_create":"2026-04-23T15:21:46.756979+08:00","gmt_modified":"2026-04-23T15:21:46.756979+08:00"},{"id":301,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#36-38","gmt_create":"2026-04-23T15:21:46.75809+08:00","gmt_modified":"2026-04-23T15:21:46.75809+08:00"},{"id":302,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-38","gmt_create":"2026-04-23T15:21:46.759234+08:00","gmt_modified":"2026-04-23T15:21:46.759234+08:00"},{"id":303,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#37-41","gmt_create":"2026-04-23T15:21:46.760054+08:00","gmt_modified":"2026-04-23T15:21:46.760054+08:00"},{"id":304,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-41","gmt_create":"2026-04-23T15:21:46.761257+08:00","gmt_modified":"2026-04-23T15:21:46.761257+08:00"},{"id":305,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-04-23T15:21:46.76204+08:00","gmt_modified":"2026-04-23T15:21:46.762041+08:00"},{"id":306,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-50","gmt_create":"2026-04-23T15:21:46.763512+08:00","gmt_modified":"2026-04-23T15:21:46.763512+08:00"},{"id":307,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"0907fc2974ec31c23aaaef02076700a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#25-33","gmt_create":"2026-04-23T15:21:46.764956+08:00","gmt_modified":"2026-04-23T15:21:46.764956+08:00"},{"id":308,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"0907fc2974ec31c23aaaef02076700a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-33","gmt_create":"2026-04-23T15:21:46.766604+08:00","gmt_modified":"2026-04-23T15:21:46.766605+08:00"},{"id":309,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"842f74e2cc054608242e93fbefd96b45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#32-40","gmt_create":"2026-04-23T15:21:46.767787+08:00","gmt_modified":"2026-04-23T15:21:46.767787+08:00"},{"id":310,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"842f74e2cc054608242e93fbefd96b45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-40","gmt_create":"2026-04-23T15:21:46.769407+08:00","gmt_modified":"2026-04-23T15:21:46.769407+08:00"},{"id":311,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"aed9e839038c45e6ce2023c4e05adb76","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#27-32","gmt_create":"2026-04-23T15:21:46.770612+08:00","gmt_modified":"2026-04-23T15:21:46.770612+08:00"},{"id":312,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"aed9e839038c45e6ce2023c4e05adb76","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-32","gmt_create":"2026-04-23T15:21:46.771344+08:00","gmt_modified":"2026-04-23T15:21:46.771345+08:00"},{"id":313,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"2181318c993526c86458f5eef134aed6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#62-77","gmt_create":"2026-04-23T15:21:46.77237+08:00","gmt_modified":"2026-04-23T15:21:46.77237+08:00"},{"id":314,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"2181318c993526c86458f5eef134aed6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 62-77","gmt_create":"2026-04-23T15:21:46.773284+08:00","gmt_modified":"2026-04-23T15:21:46.773284+08:00"},{"id":315,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"a817488dc968d761a8977fb5bb8d01a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-129","gmt_create":"2026-04-23T15:21:46.774203+08:00","gmt_modified":"2026-04-23T15:21:46.774203+08:00"},{"id":316,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"a817488dc968d761a8977fb5bb8d01a2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-129","gmt_create":"2026-04-23T15:21:46.775081+08:00","gmt_modified":"2026-04-23T15:21:46.775081+08:00"},{"id":317,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T15:21:46.775898+08:00","gmt_modified":"2026-04-23T15:21:46.775898+08:00"},{"id":318,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7","gmt_create":"2026-04-23T15:21:46.777494+08:00","gmt_modified":"2026-04-23T15:21:46.777494+08:00"},{"id":319,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7","gmt_create":"2026-04-23T15:21:46.778103+08:00","gmt_modified":"2026-04-23T15:21:46.778103+08:00"},{"id":320,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-23T15:21:46.779313+08:00","gmt_modified":"2026-04-23T15:21:46.779314+08:00"},{"id":321,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T15:21:46.780075+08:00","gmt_modified":"2026-04-23T15:21:46.780075+08:00"},{"id":322,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"37868a5af96edcdad149caf9a184435a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#42-85","gmt_create":"2026-04-23T15:21:46.781141+08:00","gmt_modified":"2026-04-23T15:21:46.781141+08:00"},{"id":323,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"37868a5af96edcdad149caf9a184435a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-85","gmt_create":"2026-04-23T15:21:46.781803+08:00","gmt_modified":"2026-04-23T15:21:46.781803+08:00"},{"id":324,"source_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#18-33","gmt_create":"2026-04-23T15:21:46.783498+08:00","gmt_modified":"2026-04-23T15:21:46.783498+08:00"},{"id":325,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-33","gmt_create":"2026-04-23T15:21:46.784342+08:00","gmt_modified":"2026-04-23T15:21:46.784343+08:00"},{"id":344,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:22:16.017503+08:00","gmt_modified":"2026-04-23T15:22:16.017503+08:00"},{"id":346,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-48","gmt_create":"2026-04-23T15:22:16.019099+08:00","gmt_modified":"2026-04-23T15:22:16.019099+08:00"},{"id":348,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-04-23T15:22:16.020577+08:00","gmt_modified":"2026-04-23T15:22:16.020577+08:00"},{"id":350,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-04-23T15:22:16.021841+08:00","gmt_modified":"2026-04-23T15:22:16.021841+08:00"},{"id":354,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-309","gmt_create":"2026-04-23T15:22:16.023827+08:00","gmt_modified":"2026-04-23T15:22:16.023827+08:00"},{"id":356,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"9630036e63fc15cb81b202cf79671aab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-182","gmt_create":"2026-04-23T15:22:16.024606+08:00","gmt_modified":"2026-04-23T15:22:16.024606+08:00"},{"id":359,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-17","gmt_create":"2026-04-23T15:22:16.026089+08:00","gmt_modified":"2026-04-23T15:22:16.02609+08:00"},{"id":361,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-123","gmt_create":"2026-04-23T15:22:16.02774+08:00","gmt_modified":"2026-04-23T15:22:16.02774+08:00"},{"id":363,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"9df233ef1be4b95068ed91bf01083ae7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 117-123","gmt_create":"2026-04-23T15:22:16.028504+08:00","gmt_modified":"2026-04-23T15:22:16.028504+08:00"},{"id":365,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-42","gmt_create":"2026-04-23T15:22:16.029449+08:00","gmt_modified":"2026-04-23T15:22:16.029449+08:00"},{"id":367,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-43","gmt_create":"2026-04-23T15:22:16.030648+08:00","gmt_modified":"2026-04-23T15:22:16.030648+08:00"},{"id":369,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-43","gmt_create":"2026-04-23T15:22:16.03168+08:00","gmt_modified":"2026-04-23T15:22:16.03168+08:00"},{"id":372,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"735aef72b4fe6ca4f407e69b7dda8b43","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-78","gmt_create":"2026-04-23T15:22:16.03298+08:00","gmt_modified":"2026-04-23T15:22:16.03298+08:00"},{"id":374,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"8128dd67cf376d2cadf7c2d3831c380a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-29","gmt_create":"2026-04-23T15:22:16.035564+08:00","gmt_modified":"2026-04-23T15:22:16.035564+08:00"},{"id":376,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-104","gmt_create":"2026-04-23T15:22:16.036753+08:00","gmt_modified":"2026-04-23T15:22:16.036753+08:00"},{"id":378,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"753a437d837246ead62b0e16c6331284","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-69","gmt_create":"2026-04-23T15:22:16.038261+08:00","gmt_modified":"2026-04-23T15:22:16.038261+08:00"},{"id":380,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-104","gmt_create":"2026-04-23T15:22:16.039369+08:00","gmt_modified":"2026-04-23T15:22:16.039369+08:00"},{"id":382,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-69","gmt_create":"2026-04-23T15:22:16.040483+08:00","gmt_modified":"2026-04-23T15:22:16.040483+08:00"},{"id":385,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 122-146","gmt_create":"2026-04-23T15:22:16.042829+08:00","gmt_modified":"2026-04-23T15:22:16.042829+08:00"},{"id":388,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"a57acd9da5287c915ac823784a409292","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-127","gmt_create":"2026-04-23T15:22:16.045132+08:00","gmt_modified":"2026-04-23T15:22:16.045132+08:00"},{"id":390,"source_id":"42ff5383133d176cec9eb88682483be3","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-93","gmt_create":"2026-04-23T15:22:16.046367+08:00","gmt_modified":"2026-04-23T15:22:16.046367+08:00"},{"id":392,"source_id":"42ff5383133d176cec9eb88682483be3","target_id":"692ac240965eff7e66945aa3c4c270f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-93","gmt_create":"2026-04-23T15:22:16.047995+08:00","gmt_modified":"2026-04-23T15:22:16.047995+08:00"},{"id":394,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"32a0a52faca2d8d488e49c63c86075b1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-154","gmt_create":"2026-04-23T15:22:16.049251+08:00","gmt_modified":"2026-04-23T15:22:16.049251+08:00"},{"id":396,"source_id":"0613e76b9679be7f998fb8fd8056e686","target_id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-154","gmt_create":"2026-04-23T15:22:16.051952+08:00","gmt_modified":"2026-04-23T15:22:16.051952+08:00"},{"id":398,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"3a6e1b738967bf8cc651e57f48e2e126","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 83-126","gmt_create":"2026-04-23T15:22:16.053692+08:00","gmt_modified":"2026-04-23T15:22:16.053693+08:00"},{"id":400,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"b1afd377757f1d0e9bdf87edfff3ad88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 131-186","gmt_create":"2026-04-23T15:22:16.054533+08:00","gmt_modified":"2026-04-23T15:22:16.054533+08:00"},{"id":402,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"de05ec7eed033e432991e5a88e1b5a06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 192-222","gmt_create":"2026-04-23T15:22:16.055495+08:00","gmt_modified":"2026-04-23T15:22:16.055495+08:00"},{"id":404,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"7fd61a451248b6b129299d6246f711c7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 228-296","gmt_create":"2026-04-23T15:22:16.056294+08:00","gmt_modified":"2026-04-23T15:22:16.056294+08:00"},{"id":406,"source_id":"80a0429cc47931de27ddb17a62b8dd9c","target_id":"53eedffff456a566fa7b0cecc7169f56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-441","gmt_create":"2026-04-23T15:22:16.05703+08:00","gmt_modified":"2026-04-23T15:22:16.05703+08:00"},{"id":408,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"906f7a8288e38d4244211f3f538fe7b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-182","gmt_create":"2026-04-23T15:22:16.062545+08:00","gmt_modified":"2026-04-23T15:22:16.062545+08:00"},{"id":410,"source_id":"b2f0d46a31a5441594f2e777365fc156","target_id":"1647ee2066de2ae59ba8cf88e33c5e02","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-123","gmt_create":"2026-04-23T15:22:16.064587+08:00","gmt_modified":"2026-04-23T15:22:16.064587+08:00"},{"id":411,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-23T15:22:23.52554+08:00","gmt_modified":"2026-04-23T15:22:23.52554+08:00"},{"id":412,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-04-23T15:22:23.52643+08:00","gmt_modified":"2026-04-23T15:22:23.526431+08:00"},{"id":413,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"f93ae024fe0a2e69698037dff6df205f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/utils.ts","gmt_create":"2026-04-23T15:22:23.527272+08:00","gmt_modified":"2026-04-23T15:22:23.527272+08:00"},{"id":414,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ac1acbc54c49ee1de13369f6c6827568","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/button.tsx","gmt_create":"2026-04-23T15:22:23.528155+08:00","gmt_modified":"2026-04-23T15:22:23.528155+08:00"},{"id":415,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"108b0c4b4dcfb6aa39a5eb138225c148","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dialog.tsx","gmt_create":"2026-04-23T15:22:23.529196+08:00","gmt_modified":"2026-04-23T15:22:23.529196+08:00"},{"id":416,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0186dc8a89340139a84e1e3c5571a57f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/dropdown-menu.tsx","gmt_create":"2026-04-23T15:22:23.530077+08:00","gmt_modified":"2026-04-23T15:22:23.530077+08:00"},{"id":417,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3cf787fa77a15b2b1783560c6d83ed21","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/input.tsx","gmt_create":"2026-04-23T15:22:23.530977+08:00","gmt_modified":"2026-04-23T15:22:23.530977+08:00"},{"id":418,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3c56e1c079959bfcc985183805e5874f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/select.tsx","gmt_create":"2026-04-23T15:22:23.531664+08:00","gmt_modified":"2026-04-23T15:22:23.531664+08:00"},{"id":419,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/card.tsx","gmt_create":"2026-04-23T15:22:23.532588+08:00","gmt_modified":"2026-04-23T15:22:23.532588+08:00"},{"id":420,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"51821ca9ec2a1c972f3c9d111e19db8a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/badge.tsx","gmt_create":"2026-04-23T15:22:23.53409+08:00","gmt_modified":"2026-04-23T15:22:23.53409+08:00"},{"id":421,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/table.tsx","gmt_create":"2026-04-23T15:22:23.535512+08:00","gmt_modified":"2026-04-23T15:22:23.535512+08:00"},{"id":422,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"beb87ab5aad9532647e9dbd2db7ef587","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/tabs.tsx","gmt_create":"2026-04-23T15:22:23.536664+08:00","gmt_modified":"2026-04-23T15:22:23.536665+08:00"},{"id":423,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"792b8e2c16c9ff2095d83b8972313be4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/label.tsx","gmt_create":"2026-04-23T15:22:23.537365+08:00","gmt_modified":"2026-04-23T15:22:23.537365+08:00"},{"id":424,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"546e01c5f73aaf5140eee922f4b9a441","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/providers.tsx","gmt_create":"2026-04-23T15:22:23.538246+08:00","gmt_modified":"2026-04-23T15:22:23.538246+08:00"},{"id":425,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-23T15:22:23.53929+08:00","gmt_modified":"2026-04-23T15:22:23.53929+08:00"},{"id":426,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-04-23T15:22:23.540469+08:00","gmt_modified":"2026-04-23T15:22:23.540469+08:00"},{"id":427,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-23T15:22:23.541484+08:00","gmt_modified":"2026-04-23T15:22:23.541484+08:00"},{"id":428,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"fd18328b6582e68c30b130b912891992","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/providers.tsx#1-9","gmt_create":"2026-04-23T15:22:23.542098+08:00","gmt_modified":"2026-04-23T15:22:23.542098+08:00"},{"id":429,"source_id":"546e01c5f73aaf5140eee922f4b9a441","target_id":"fd18328b6582e68c30b130b912891992","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-9","gmt_create":"2026-04-23T15:22:23.542482+08:00","gmt_modified":"2026-04-23T15:22:23.542482+08:00"},{"id":430,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"dcfa308ef4ec368c5a51a17acbfc8e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#1-7","gmt_create":"2026-04-23T15:22:23.542958+08:00","gmt_modified":"2026-04-23T15:22:23.542958+08:00"},{"id":431,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-23T15:22:23.54348+08:00","gmt_modified":"2026-04-23T15:22:23.54348+08:00"},{"id":432,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-40","gmt_create":"2026-04-23T15:22:23.543767+08:00","gmt_modified":"2026-04-23T15:22:23.543768+08:00"},{"id":433,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-57","gmt_create":"2026-04-23T15:22:23.544176+08:00","gmt_modified":"2026-04-23T15:22:23.544176+08:00"},{"id":434,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:22:23.544513+08:00","gmt_modified":"2026-04-23T15:22:23.544513+08:00"},{"id":435,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#1-57","gmt_create":"2026-04-23T15:22:23.545023+08:00","gmt_modified":"2026-04-23T15:22:23.545023+08:00"},{"id":436,"source_id":"ac1acbc54c49ee1de13369f6c6827568","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-23T15:22:23.545376+08:00","gmt_modified":"2026-04-23T15:22:23.545376+08:00"},{"id":437,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"607bb628918a7a5d54cbf74763f94d07","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/input.tsx#1-23","gmt_create":"2026-04-23T15:22:23.545898+08:00","gmt_modified":"2026-04-23T15:22:23.545899+08:00"},{"id":438,"source_id":"3cf787fa77a15b2b1783560c6d83ed21","target_id":"607bb628918a7a5d54cbf74763f94d07","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T15:22:23.546272+08:00","gmt_modified":"2026-04-23T15:22:23.546272+08:00"},{"id":439,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/select.tsx#1-161","gmt_create":"2026-04-23T15:22:23.546653+08:00","gmt_modified":"2026-04-23T15:22:23.546653+08:00"},{"id":440,"source_id":"3c56e1c079959bfcc985183805e5874f","target_id":"325e25d1dda0f7bfd9d7adfe35ecf3b5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-161","gmt_create":"2026-04-23T15:22:23.546906+08:00","gmt_modified":"2026-04-23T15:22:23.546907+08:00"},{"id":441,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0eed9f61572209dd754611fc7c690d5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#1-123","gmt_create":"2026-04-23T15:22:23.547243+08:00","gmt_modified":"2026-04-23T15:22:23.547244+08:00"},{"id":442,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ad6ff021b2126ad5c42323305eb6d8b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dropdown-menu.tsx#1-201","gmt_create":"2026-04-23T15:22:23.547645+08:00","gmt_modified":"2026-04-23T15:22:23.547645+08:00"},{"id":443,"source_id":"0186dc8a89340139a84e1e3c5571a57f","target_id":"ad6ff021b2126ad5c42323305eb6d8b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-201","gmt_create":"2026-04-23T15:22:23.547892+08:00","gmt_modified":"2026-04-23T15:22:23.547892+08:00"},{"id":444,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"a85f004dca63614b4e734ba63b45ef9e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/card.tsx#1-80","gmt_create":"2026-04-23T15:22:23.548296+08:00","gmt_modified":"2026-04-23T15:22:23.548296+08:00"},{"id":445,"source_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","target_id":"a85f004dca63614b4e734ba63b45ef9e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-80","gmt_create":"2026-04-23T15:22:23.548561+08:00","gmt_modified":"2026-04-23T15:22:23.548561+08:00"},{"id":446,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"3bab92a09e9fb456e0303bb1e04afc7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#1-118","gmt_create":"2026-04-23T15:22:23.548946+08:00","gmt_modified":"2026-04-23T15:22:23.548946+08:00"},{"id":447,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#1-56","gmt_create":"2026-04-23T15:22:23.549383+08:00","gmt_modified":"2026-04-23T15:22:23.549383+08:00"},{"id":448,"source_id":"beb87ab5aad9532647e9dbd2db7ef587","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-56","gmt_create":"2026-04-23T15:22:23.549652+08:00","gmt_modified":"2026-04-23T15:22:23.549653+08:00"},{"id":449,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"379443f450513b5492e2d9d5fca94a42","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/label.tsx#1-27","gmt_create":"2026-04-23T15:22:23.550013+08:00","gmt_modified":"2026-04-23T15:22:23.550014+08:00"},{"id":450,"source_id":"792b8e2c16c9ff2095d83b8972313be4","target_id":"379443f450513b5492e2d9d5fca94a42","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-27","gmt_create":"2026-04-23T15:22:23.550267+08:00","gmt_modified":"2026-04-23T15:22:23.550267+08:00"},{"id":451,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4aa6ad434a73143bb7a2072124f63be0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/badge.tsx#1-37","gmt_create":"2026-04-23T15:22:23.551155+08:00","gmt_modified":"2026-04-23T15:22:23.551155+08:00"},{"id":452,"source_id":"51821ca9ec2a1c972f3c9d111e19db8a","target_id":"4aa6ad434a73143bb7a2072124f63be0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T15:22:23.551858+08:00","gmt_modified":"2026-04-23T15:22:23.551858+08:00"},{"id":453,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"c45dbdda70a8b9f02b52af4991644d0b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#11-27","gmt_create":"2026-04-23T15:22:23.552353+08:00","gmt_modified":"2026-04-23T15:22:23.552353+08:00"},{"id":454,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"c45dbdda70a8b9f02b52af4991644d0b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-27","gmt_create":"2026-04-23T15:22:23.552845+08:00","gmt_modified":"2026-04-23T15:22:23.552845+08:00"},{"id":455,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"6ac6943c93570294e4fb15a862be2616","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#36-54","gmt_create":"2026-04-23T15:22:23.553797+08:00","gmt_modified":"2026-04-23T15:22:23.553797+08:00"},{"id":456,"source_id":"ac1acbc54c49ee1de13369f6c6827568","target_id":"6ac6943c93570294e4fb15a862be2616","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-54","gmt_create":"2026-04-23T15:22:23.554077+08:00","gmt_modified":"2026-04-23T15:22:23.554077+08:00"},{"id":457,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4bfb5059c685e9878aed64cb5347ccec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#9-54","gmt_create":"2026-04-23T15:22:23.554645+08:00","gmt_modified":"2026-04-23T15:22:23.554645+08:00"},{"id":458,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"4bfb5059c685e9878aed64cb5347ccec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-54","gmt_create":"2026-04-23T15:22:23.554875+08:00","gmt_modified":"2026-04-23T15:22:23.554875+08:00"},{"id":459,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"0af48b69fe8fb9e480fa1656f36a4330","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dropdown-menu.tsx#21-75","gmt_create":"2026-04-23T15:22:23.555418+08:00","gmt_modified":"2026-04-23T15:22:23.555418+08:00"},{"id":460,"source_id":"0186dc8a89340139a84e1e3c5571a57f","target_id":"0af48b69fe8fb9e480fa1656f36a4330","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-75","gmt_create":"2026-04-23T15:22:23.55574+08:00","gmt_modified":"2026-04-23T15:22:23.55574+08:00"},{"id":461,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"09971e31ab658e119d4c0ad948282107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/select.tsx#15-100","gmt_create":"2026-04-23T15:22:23.556401+08:00","gmt_modified":"2026-04-23T15:22:23.556401+08:00"},{"id":462,"source_id":"3c56e1c079959bfcc985183805e5874f","target_id":"09971e31ab658e119d4c0ad948282107","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-100","gmt_create":"2026-04-23T15:22:23.556634+08:00","gmt_modified":"2026-04-23T15:22:23.556634+08:00"},{"id":463,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"31aa8777de6043883950d2668094e388","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/table.tsx#5-106","gmt_create":"2026-04-23T15:22:23.55717+08:00","gmt_modified":"2026-04-23T15:22:23.55717+08:00"},{"id":464,"source_id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","target_id":"31aa8777de6043883950d2668094e388","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-106","gmt_create":"2026-04-23T15:22:23.557428+08:00","gmt_modified":"2026-04-23T15:22:23.557429+08:00"},{"id":465,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"28baf3cedb89a21c6d542b7ce2439b24","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#8-53","gmt_create":"2026-04-23T15:22:23.558002+08:00","gmt_modified":"2026-04-23T15:22:23.558002+08:00"},{"id":466,"source_id":"beb87ab5aad9532647e9dbd2db7ef587","target_id":"28baf3cedb89a21c6d542b7ce2439b24","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-53","gmt_create":"2026-04-23T15:22:23.558316+08:00","gmt_modified":"2026-04-23T15:22:23.558316+08:00"},{"id":467,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"28b0f4797c6084272244175a24b961cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/card.tsx#5-77","gmt_create":"2026-04-23T15:22:23.558858+08:00","gmt_modified":"2026-04-23T15:22:23.558858+08:00"},{"id":468,"source_id":"0d5ef537f7c0b8c390f8b31d7cf47b56","target_id":"28b0f4797c6084272244175a24b961cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-77","gmt_create":"2026-04-23T15:22:23.559082+08:00","gmt_modified":"2026-04-23T15:22:23.559082+08:00"},{"id":469,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"a6e0b3fa65906c3c3cd88707e1d40059","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/label.tsx#9-23","gmt_create":"2026-04-23T15:22:23.559653+08:00","gmt_modified":"2026-04-23T15:22:23.559653+08:00"},{"id":470,"source_id":"792b8e2c16c9ff2095d83b8972313be4","target_id":"a6e0b3fa65906c3c3cd88707e1d40059","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-23","gmt_create":"2026-04-23T15:22:23.560391+08:00","gmt_modified":"2026-04-23T15:22:23.560392+08:00"},{"id":471,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"9a909775022010b4686c2b00cdf1c165","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/badge.tsx#6-34","gmt_create":"2026-04-23T15:22:23.562216+08:00","gmt_modified":"2026-04-23T15:22:23.562216+08:00"},{"id":472,"source_id":"51821ca9ec2a1c972f3c9d111e19db8a","target_id":"9a909775022010b4686c2b00cdf1c165","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-34","gmt_create":"2026-04-23T15:22:23.562602+08:00","gmt_modified":"2026-04-23T15:22:23.562602+08:00"},{"id":473,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"ce1cd184945ae56cf63f55168afd8050","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/dialog.tsx#47-50","gmt_create":"2026-04-23T15:22:23.565009+08:00","gmt_modified":"2026-04-23T15:22:23.565009+08:00"},{"id":474,"source_id":"108b0c4b4dcfb6aa39a5eb138225c148","target_id":"ce1cd184945ae56cf63f55168afd8050","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-50","gmt_create":"2026-04-23T15:22:23.565469+08:00","gmt_modified":"2026-04-23T15:22:23.565469+08:00"},{"id":475,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"4a2a06e1efcbc85deaa013dca155f20c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#10-54","gmt_create":"2026-04-23T15:22:23.57102+08:00","gmt_modified":"2026-04-23T15:22:23.57102+08:00"},{"id":476,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"4a2a06e1efcbc85deaa013dca155f20c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-54","gmt_create":"2026-04-23T15:22:23.571491+08:00","gmt_modified":"2026-04-23T15:22:23.571491+08:00"},{"id":477,"source_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","target_id":"8b00ea4aba57ea6ed982287fb7840805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/utils.ts#4-6","gmt_create":"2026-04-23T15:22:23.572188+08:00","gmt_modified":"2026-04-23T15:22:23.572188+08:00"},{"id":478,"source_id":"f93ae024fe0a2e69698037dff6df205f","target_id":"8b00ea4aba57ea6ed982287fb7840805","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-6","gmt_create":"2026-04-23T15:22:23.572722+08:00","gmt_modified":"2026-04-23T15:22:23.572722+08:00"},{"id":483,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"2fc79486-ec65-4533-860a-89c8877c2ea0","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e 2fc79486-ec65-4533-860a-89c8877c2ea0","gmt_create":"2026-04-23T15:22:24.563092+08:00","gmt_modified":"2026-04-23T15:22:24.563092+08:00"},{"id":484,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","gmt_create":"2026-04-23T15:22:24.564188+08:00","gmt_modified":"2026-04-23T15:22:24.564188+08:00"},{"id":492,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:31:36.520458+08:00","gmt_modified":"2026-04-23T20:31:36.520458+08:00"},{"id":493,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:31:36.521676+08:00","gmt_modified":"2026-04-23T20:31:36.521677+08:00"},{"id":494,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:31:36.522472+08:00","gmt_modified":"2026-04-23T20:31:36.522472+08:00"},{"id":495,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:31:36.522898+08:00","gmt_modified":"2026-04-23T20:31:36.522898+08:00"},{"id":496,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"404f6d0765a8c6e77e33b7fc21b377a4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/doubao.py","gmt_create":"2026-04-23T20:31:36.523305+08:00","gmt_modified":"2026-04-23T20:31:36.523305+08:00"},{"id":497,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"303e80519e946904d1cb3ac32cbb0814","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/qingyan.py","gmt_create":"2026-04-23T20:31:36.524292+08:00","gmt_modified":"2026-04-23T20:31:36.524292+08:00"},{"id":498,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"5af7301fe056fc3d10820d820e8ad777","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tiangong.py","gmt_create":"2026-04-23T20:31:36.525283+08:00","gmt_modified":"2026-04-23T20:31:36.525283+08:00"},{"id":499,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"0e38ad5d2d3daaad08c9302df8805b15","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/xinghuo.py","gmt_create":"2026-04-23T20:31:36.52736+08:00","gmt_modified":"2026-04-23T20:31:36.52736+08:00"},{"id":500,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:31:36.527985+08:00","gmt_modified":"2026-04-23T20:31:36.527985+08:00"},{"id":501,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:31:36.530076+08:00","gmt_modified":"2026-04-23T20:31:36.530076+08:00"},{"id":502,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:31:36.531496+08:00","gmt_modified":"2026-04-23T20:31:36.531496+08:00"},{"id":503,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:31:36.532308+08:00","gmt_modified":"2026-04-23T20:31:36.532308+08:00"},{"id":504,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:31:36.533202+08:00","gmt_modified":"2026-04-23T20:31:36.533203+08:00"},{"id":505,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:31:36.533733+08:00","gmt_modified":"2026-04-23T20:31:36.533733+08:00"},{"id":506,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:31:36.534166+08:00","gmt_modified":"2026-04-23T20:31:36.534166+08:00"},{"id":507,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:31:36.535208+08:00","gmt_modified":"2026-04-23T20:31:36.535208+08:00"},{"id":508,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:31:36.536177+08:00","gmt_modified":"2026-04-23T20:31:36.536177+08:00"},{"id":509,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T20:31:36.536784+08:00","gmt_modified":"2026-04-23T20:31:36.536784+08:00"},{"id":510,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-04-23T20:31:36.537249+08:00","gmt_modified":"2026-04-23T20:31:36.537249+08:00"},{"id":511,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-23T20:31:36.53817+08:00","gmt_modified":"2026-04-23T20:31:36.538171+08:00"},{"id":512,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T20:31:36.53929+08:00","gmt_modified":"2026-04-23T20:31:36.53929+08:00"},{"id":513,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-269","gmt_create":"2026-04-23T20:31:36.540413+08:00","gmt_modified":"2026-04-23T20:31:36.540413+08:00"},{"id":514,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-269","gmt_create":"2026-04-23T20:31:36.541301+08:00","gmt_modified":"2026-04-23T20:31:36.541301+08:00"},{"id":515,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:31:36.541996+08:00","gmt_modified":"2026-04-23T20:31:36.541996+08:00"},{"id":516,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-95","gmt_create":"2026-04-23T20:31:36.542269+08:00","gmt_modified":"2026-04-23T20:31:36.542269+08:00"},{"id":517,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-330","gmt_create":"2026-04-23T20:31:36.543463+08:00","gmt_modified":"2026-04-23T20:31:36.543463+08:00"},{"id":518,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-330","gmt_create":"2026-04-23T20:31:36.543912+08:00","gmt_modified":"2026-04-23T20:31:36.543912+08:00"},{"id":519,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#1-38","gmt_create":"2026-04-23T20:31:36.545278+08:00","gmt_modified":"2026-04-23T20:31:36.545279+08:00"},{"id":520,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.545752+08:00","gmt_modified":"2026-04-23T20:31:36.545752+08:00"},{"id":521,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#1-38","gmt_create":"2026-04-23T20:31:36.546456+08:00","gmt_modified":"2026-04-23T20:31:36.546457+08:00"},{"id":522,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.546804+08:00","gmt_modified":"2026-04-23T20:31:36.546804+08:00"},{"id":523,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#1-38","gmt_create":"2026-04-23T20:31:36.547594+08:00","gmt_modified":"2026-04-23T20:31:36.547594+08:00"},{"id":524,"source_id":"303e80519e946904d1cb3ac32cbb0814","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.548009+08:00","gmt_modified":"2026-04-23T20:31:36.548009+08:00"},{"id":525,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#1-38","gmt_create":"2026-04-23T20:31:36.548333+08:00","gmt_modified":"2026-04-23T20:31:36.548333+08:00"},{"id":526,"source_id":"5af7301fe056fc3d10820d820e8ad777","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.548917+08:00","gmt_modified":"2026-04-23T20:31:36.548917+08:00"},{"id":527,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#1-38","gmt_create":"2026-04-23T20:31:36.549296+08:00","gmt_modified":"2026-04-23T20:31:36.549296+08:00"},{"id":528,"source_id":"0e38ad5d2d3daaad08c9302df8805b15","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-04-23T20:31:36.54956+08:00","gmt_modified":"2026-04-23T20:31:36.54956+08:00"},{"id":529,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:31:36.549907+08:00","gmt_modified":"2026-04-23T20:31:36.549907+08:00"},{"id":530,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-174","gmt_create":"2026-04-23T20:31:36.55085+08:00","gmt_modified":"2026-04-23T20:31:36.55085+08:00"},{"id":531,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-23T20:31:36.551428+08:00","gmt_modified":"2026-04-23T20:31:36.551428+08:00"},{"id":532,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:31:36.552386+08:00","gmt_modified":"2026-04-23T20:31:36.552386+08:00"},{"id":533,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-55","gmt_create":"2026-04-23T20:31:36.553134+08:00","gmt_modified":"2026-04-23T20:31:36.553134+08:00"},{"id":534,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:31:36.553656+08:00","gmt_modified":"2026-04-23T20:31:36.553656+08:00"},{"id":535,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-42","gmt_create":"2026-04-23T20:31:36.554174+08:00","gmt_modified":"2026-04-23T20:31:36.554174+08:00"},{"id":536,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:31:36.555503+08:00","gmt_modified":"2026-04-23T20:31:36.555503+08:00"},{"id":537,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-39","gmt_create":"2026-04-23T20:31:36.556658+08:00","gmt_modified":"2026-04-23T20:31:36.556658+08:00"},{"id":538,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:31:36.558991+08:00","gmt_modified":"2026-04-23T20:31:36.558991+08:00"},{"id":539,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-18","gmt_create":"2026-04-23T20:31:36.559781+08:00","gmt_modified":"2026-04-23T20:31:36.559781+08:00"},{"id":540,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"300e43c7a648440163f81039eaa47b5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-24","gmt_create":"2026-04-23T20:31:36.563289+08:00","gmt_modified":"2026-04-23T20:31:36.563289+08:00"},{"id":541,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"300e43c7a648440163f81039eaa47b5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-24","gmt_create":"2026-04-23T20:31:36.563813+08:00","gmt_modified":"2026-04-23T20:31:36.563813+08:00"},{"id":542,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"caf1970ded8fc5d3921005e166e2100b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-78","gmt_create":"2026-04-23T20:31:36.567359+08:00","gmt_modified":"2026-04-23T20:31:36.567359+08:00"},{"id":543,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"caf1970ded8fc5d3921005e166e2100b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-78","gmt_create":"2026-04-23T20:31:36.567845+08:00","gmt_modified":"2026-04-23T20:31:36.567845+08:00"},{"id":544,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-234","gmt_create":"2026-04-23T20:31:36.568622+08:00","gmt_modified":"2026-04-23T20:31:36.568622+08:00"},{"id":545,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 204-234","gmt_create":"2026-04-23T20:31:36.569217+08:00","gmt_modified":"2026-04-23T20:31:36.569217+08:00"},{"id":546,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:31:36.569785+08:00","gmt_modified":"2026-04-23T20:31:36.569785+08:00"},{"id":547,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-84","gmt_create":"2026-04-23T20:31:36.570169+08:00","gmt_modified":"2026-04-23T20:31:36.570169+08:00"},{"id":548,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:31:36.570576+08:00","gmt_modified":"2026-04-23T20:31:36.570576+08:00"},{"id":549,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"362d22f423631cda39404660b3317a2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 177-254","gmt_create":"2026-04-23T20:31:36.571472+08:00","gmt_modified":"2026-04-23T20:31:36.571472+08:00"},{"id":550,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#16-33","gmt_create":"2026-04-23T20:31:36.572484+08:00","gmt_modified":"2026-04-23T20:31:36.572484+08:00"},{"id":551,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:31:36.573312+08:00","gmt_modified":"2026-04-23T20:31:36.573312+08:00"},{"id":552,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:31:36.574111+08:00","gmt_modified":"2026-04-23T20:31:36.574112+08:00"},{"id":553,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 163-174","gmt_create":"2026-04-23T20:31:36.574746+08:00","gmt_modified":"2026-04-23T20:31:36.574746+08:00"},{"id":554,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"75c6ab0599d304bf36d290d4143d3d2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#29-31","gmt_create":"2026-04-23T20:31:36.590144+08:00","gmt_modified":"2026-04-23T20:31:36.590144+08:00"},{"id":555,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"75c6ab0599d304bf36d290d4143d3d2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-31","gmt_create":"2026-04-23T20:31:36.591214+08:00","gmt_modified":"2026-04-23T20:31:36.591214+08:00"},{"id":556,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:31:36.591664+08:00","gmt_modified":"2026-04-23T20:31:36.591664+08:00"},{"id":557,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:31:36.592665+08:00","gmt_modified":"2026-04-23T20:31:36.592666+08:00"},{"id":558,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2a6780838f1415dcb7d0fa611f64cee7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-17","gmt_create":"2026-04-23T20:31:36.593186+08:00","gmt_modified":"2026-04-23T20:31:36.593186+08:00"},{"id":559,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"2a6780838f1415dcb7d0fa611f64cee7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-17","gmt_create":"2026-04-23T20:31:36.59372+08:00","gmt_modified":"2026-04-23T20:31:36.59372+08:00"},{"id":560,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#10-38","gmt_create":"2026-04-23T20:31:36.595227+08:00","gmt_modified":"2026-04-23T20:31:36.595227+08:00"},{"id":561,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.596503+08:00","gmt_modified":"2026-04-23T20:31:36.596503+08:00"},{"id":562,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"aa8c3fa3bc509dafe64d113bdd09eafa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#10-38","gmt_create":"2026-04-23T20:31:36.597069+08:00","gmt_modified":"2026-04-23T20:31:36.597069+08:00"},{"id":563,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"aa8c3fa3bc509dafe64d113bdd09eafa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.597765+08:00","gmt_modified":"2026-04-23T20:31:36.597765+08:00"},{"id":564,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"eabb031e538ea62cab69b01368740d20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#10-38","gmt_create":"2026-04-23T20:31:36.598445+08:00","gmt_modified":"2026-04-23T20:31:36.598445+08:00"},{"id":565,"source_id":"303e80519e946904d1cb3ac32cbb0814","target_id":"eabb031e538ea62cab69b01368740d20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.599093+08:00","gmt_modified":"2026-04-23T20:31:36.599093+08:00"},{"id":566,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b1c09e372a63e9854886adaea1663bea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#10-38","gmt_create":"2026-04-23T20:31:36.599896+08:00","gmt_modified":"2026-04-23T20:31:36.599896+08:00"},{"id":567,"source_id":"5af7301fe056fc3d10820d820e8ad777","target_id":"b1c09e372a63e9854886adaea1663bea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.600604+08:00","gmt_modified":"2026-04-23T20:31:36.600604+08:00"},{"id":568,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"79793bcd507f9d287d19014b60d963d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#10-38","gmt_create":"2026-04-23T20:31:36.601204+08:00","gmt_modified":"2026-04-23T20:31:36.601204+08:00"},{"id":569,"source_id":"0e38ad5d2d3daaad08c9302df8805b15","target_id":"79793bcd507f9d287d19014b60d963d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:36.60148+08:00","gmt_modified":"2026-04-23T20:31:36.60148+08:00"},{"id":570,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-144","gmt_create":"2026-04-23T20:31:36.603752+08:00","gmt_modified":"2026-04-23T20:31:36.603752+08:00"},{"id":571,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-144","gmt_create":"2026-04-23T20:31:36.606514+08:00","gmt_modified":"2026-04-23T20:31:36.606514+08:00"},{"id":572,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:31:36.609013+08:00","gmt_modified":"2026-04-23T20:31:36.609013+08:00"},{"id":573,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 256-287","gmt_create":"2026-04-23T20:31:36.609501+08:00","gmt_modified":"2026-04-23T20:31:36.609501+08:00"},{"id":574,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"8af91caf063c12c8236f9675769ce4a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#1-54","gmt_create":"2026-04-23T20:31:36.610558+08:00","gmt_modified":"2026-04-23T20:31:36.610558+08:00"},{"id":575,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"8af91caf063c12c8236f9675769ce4a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-54","gmt_create":"2026-04-23T20:31:36.610946+08:00","gmt_modified":"2026-04-23T20:31:36.610946+08:00"},{"id":576,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"005172b71dc742cf6803c5eb0185091e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-36","gmt_create":"2026-04-23T20:31:36.612653+08:00","gmt_modified":"2026-04-23T20:31:36.612653+08:00"},{"id":577,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"005172b71dc742cf6803c5eb0185091e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-36","gmt_create":"2026-04-23T20:31:36.613263+08:00","gmt_modified":"2026-04-23T20:31:36.613263+08:00"},{"id":578,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:31:36.614861+08:00","gmt_modified":"2026-04-23T20:31:36.614861+08:00"},{"id":579,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 139-144","gmt_create":"2026-04-23T20:31:36.615692+08:00","gmt_modified":"2026-04-23T20:31:36.615692+08:00"},{"id":580,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"384b1939e53970ce7ae75d241a49da5f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#22-29","gmt_create":"2026-04-23T20:31:36.615996+08:00","gmt_modified":"2026-04-23T20:31:36.615996+08:00"},{"id":581,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"384b1939e53970ce7ae75d241a49da5f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-29","gmt_create":"2026-04-23T20:31:36.61682+08:00","gmt_modified":"2026-04-23T20:31:36.61682+08:00"},{"id":582,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:31:36.617171+08:00","gmt_modified":"2026-04-23T20:31:36.617171+08:00"},{"id":583,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 231-247","gmt_create":"2026-04-23T20:31:36.617385+08:00","gmt_modified":"2026-04-23T20:31:36.617385+08:00"},{"id":584,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"15b8ebf74b0a5dfac58024d323ca8d0a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#164-175","gmt_create":"2026-04-23T20:31:36.618327+08:00","gmt_modified":"2026-04-23T20:31:36.618327+08:00"},{"id":585,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"15b8ebf74b0a5dfac58024d323ca8d0a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 164-175","gmt_create":"2026-04-23T20:31:36.618609+08:00","gmt_modified":"2026-04-23T20:31:36.618609+08:00"},{"id":586,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:31:50.473102+08:00","gmt_modified":"2026-04-23T20:31:50.473102+08:00"},{"id":587,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:31:50.473614+08:00","gmt_modified":"2026-04-23T20:31:50.473614+08:00"},{"id":588,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:31:50.474171+08:00","gmt_modified":"2026-04-23T20:31:50.474171+08:00"},{"id":589,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:31:50.474429+08:00","gmt_modified":"2026-04-23T20:31:50.474429+08:00"},{"id":590,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:31:50.474658+08:00","gmt_modified":"2026-04-23T20:31:50.474658+08:00"},{"id":591,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:31:50.474883+08:00","gmt_modified":"2026-04-23T20:31:50.474883+08:00"},{"id":592,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:31:50.475158+08:00","gmt_modified":"2026-04-23T20:31:50.475158+08:00"},{"id":593,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-04-23T20:31:50.475559+08:00","gmt_modified":"2026-04-23T20:31:50.475559+08:00"},{"id":594,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:31:50.475799+08:00","gmt_modified":"2026-04-23T20:31:50.475799+08:00"},{"id":595,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:31:50.47602+08:00","gmt_modified":"2026-04-23T20:31:50.47602+08:00"},{"id":596,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"42ff5383133d176cec9eb88682483be3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citations.py","gmt_create":"2026-04-23T20:31:50.476237+08:00","gmt_modified":"2026-04-23T20:31:50.476237+08:00"},{"id":597,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:31:50.476528+08:00","gmt_modified":"2026-04-23T20:31:50.476528+08:00"},{"id":598,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"bcfade20d923c8efa713808ca9af94ca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#10-38","gmt_create":"2026-04-23T20:31:50.476982+08:00","gmt_modified":"2026-04-23T20:31:50.476982+08:00"},{"id":599,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"bcfade20d923c8efa713808ca9af94ca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:50.477216+08:00","gmt_modified":"2026-04-23T20:31:50.477216+08:00"},{"id":600,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"ca7e1232fbba5fb75e04ab8e491bfbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#10-38","gmt_create":"2026-04-23T20:31:50.477565+08:00","gmt_modified":"2026-04-23T20:31:50.477565+08:00"},{"id":601,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"ca7e1232fbba5fb75e04ab8e491bfbd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-38","gmt_create":"2026-04-23T20:31:50.477978+08:00","gmt_modified":"2026-04-23T20:31:50.477978+08:00"},{"id":602,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"c5ae7697193b2b93425ff25d2d7d54a9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#10-38","gmt_create":"2026-04-23T20:31:50.478592+08:00","gmt_modified":"2026-04-23T20:31:50.478592+08:00"},{"id":603,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:31:50.479311+08:00","gmt_modified":"2026-04-23T20:31:50.479311+08:00"},{"id":604,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"9720b93ed7247efb685e2825e5f964bf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-176","gmt_create":"2026-04-23T20:31:50.479856+08:00","gmt_modified":"2026-04-23T20:31:50.479856+08:00"},{"id":605,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"9720b93ed7247efb685e2825e5f964bf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-176","gmt_create":"2026-04-23T20:31:50.48037+08:00","gmt_modified":"2026-04-23T20:31:50.48037+08:00"},{"id":606,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"0d226400124ba891a46f59c36781ccd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-23","gmt_create":"2026-04-23T20:31:50.481311+08:00","gmt_modified":"2026-04-23T20:31:50.481311+08:00"},{"id":607,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"0d226400124ba891a46f59c36781ccd8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-23","gmt_create":"2026-04-23T20:31:50.481625+08:00","gmt_modified":"2026-04-23T20:31:50.481625+08:00"},{"id":608,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"412695e5de2014514a8f62f98c573656","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#1-41","gmt_create":"2026-04-23T20:31:50.482236+08:00","gmt_modified":"2026-04-23T20:31:50.482236+08:00"},{"id":609,"source_id":"e9b52adbec3c07cf021e488dd3f99ab4","target_id":"412695e5de2014514a8f62f98c573656","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-23T20:31:50.483281+08:00","gmt_modified":"2026-04-23T20:31:50.483281+08:00"},{"id":610,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:31:50.483853+08:00","gmt_modified":"2026-04-23T20:31:50.483854+08:00"},{"id":611,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"485e15eb30a5b08da38a628c9dd5053e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#16-77","gmt_create":"2026-04-23T20:31:50.48646+08:00","gmt_modified":"2026-04-23T20:31:50.48646+08:00"},{"id":612,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"485e15eb30a5b08da38a628c9dd5053e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-77","gmt_create":"2026-04-23T20:31:50.486841+08:00","gmt_modified":"2026-04-23T20:31:50.486841+08:00"},{"id":613,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:31:50.487399+08:00","gmt_modified":"2026-04-23T20:31:50.487399+08:00"},{"id":614,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:31:50.488281+08:00","gmt_modified":"2026-04-23T20:31:50.488281+08:00"},{"id":615,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-33","gmt_create":"2026-04-23T20:31:50.488807+08:00","gmt_modified":"2026-04-23T20:31:50.488807+08:00"},{"id":616,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:31:50.489038+08:00","gmt_modified":"2026-04-23T20:31:50.489038+08:00"},{"id":617,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"5c3f336b5a7b4af4cc2f2ac183539218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-145","gmt_create":"2026-04-23T20:31:50.491706+08:00","gmt_modified":"2026-04-23T20:31:50.491706+08:00"},{"id":618,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"5c3f336b5a7b4af4cc2f2ac183539218","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-145","gmt_create":"2026-04-23T20:31:50.492445+08:00","gmt_modified":"2026-04-23T20:31:50.492445+08:00"},{"id":619,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"3894c1ed9dca2ebf2359f40ebdb1959e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#147-174","gmt_create":"2026-04-23T20:31:50.493129+08:00","gmt_modified":"2026-04-23T20:31:50.493129+08:00"},{"id":620,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"3894c1ed9dca2ebf2359f40ebdb1959e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 147-174","gmt_create":"2026-04-23T20:31:50.493716+08:00","gmt_modified":"2026-04-23T20:31:50.493716+08:00"},{"id":621,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:31:50.494347+08:00","gmt_modified":"2026-04-23T20:31:50.494348+08:00"},{"id":622,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-109","gmt_create":"2026-04-23T20:31:50.496521+08:00","gmt_modified":"2026-04-23T20:31:50.496521+08:00"},{"id":623,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-109","gmt_create":"2026-04-23T20:31:50.496915+08:00","gmt_modified":"2026-04-23T20:31:50.496915+08:00"},{"id":624,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"5f893f5078aa8e549284feb057aa45da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-29","gmt_create":"2026-04-23T20:31:50.499115+08:00","gmt_modified":"2026-04-23T20:31:50.499115+08:00"},{"id":625,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"5f893f5078aa8e549284feb057aa45da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-29","gmt_create":"2026-04-23T20:31:50.49944+08:00","gmt_modified":"2026-04-23T20:31:50.49944+08:00"},{"id":626,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:31:50.50016+08:00","gmt_modified":"2026-04-23T20:31:50.50016+08:00"},{"id":627,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e0b68d2d24760689a0f4f00dfee5f9f2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#28-76","gmt_create":"2026-04-23T20:31:50.500908+08:00","gmt_modified":"2026-04-23T20:31:50.500908+08:00"},{"id":628,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"e0b68d2d24760689a0f4f00dfee5f9f2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-76","gmt_create":"2026-04-23T20:31:50.501388+08:00","gmt_modified":"2026-04-23T20:31:50.501388+08:00"},{"id":629,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"e9b98ae83632342d8e06cde39e9c9462","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#105-137","gmt_create":"2026-04-23T20:31:50.502229+08:00","gmt_modified":"2026-04-23T20:31:50.502229+08:00"},{"id":630,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"e9b98ae83632342d8e06cde39e9c9462","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 105-137","gmt_create":"2026-04-23T20:31:50.502758+08:00","gmt_modified":"2026-04-23T20:31:50.502758+08:00"},{"id":631,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:31:50.503532+08:00","gmt_modified":"2026-04-23T20:31:50.503532+08:00"},{"id":632,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#23-93","gmt_create":"2026-04-23T20:31:50.504205+08:00","gmt_modified":"2026-04-23T20:31:50.504206+08:00"},{"id":633,"source_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-109","gmt_create":"2026-04-23T20:31:50.504719+08:00","gmt_modified":"2026-04-23T20:31:50.504719+08:00"},{"id":634,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 90-109","gmt_create":"2026-04-23T20:31:50.505358+08:00","gmt_modified":"2026-04-23T20:31:50.505358+08:00"},{"id":635,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:30.005285+08:00","gmt_modified":"2026-04-23T20:33:30.005285+08:00"},{"id":636,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:30.006785+08:00","gmt_modified":"2026-04-23T20:33:30.006785+08:00"},{"id":637,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:30.008852+08:00","gmt_modified":"2026-04-23T20:33:30.008852+08:00"},{"id":638,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:30.010802+08:00","gmt_modified":"2026-04-23T20:33:30.010803+08:00"},{"id":639,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:30.011496+08:00","gmt_modified":"2026-04-23T20:33:30.011496+08:00"},{"id":640,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-23T20:33:30.012521+08:00","gmt_modified":"2026-04-23T20:33:30.012521+08:00"},{"id":641,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:33:30.013288+08:00","gmt_modified":"2026-04-23T20:33:30.013288+08:00"},{"id":642,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:30.014048+08:00","gmt_modified":"2026-04-23T20:33:30.014048+08:00"},{"id":643,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:30.014998+08:00","gmt_modified":"2026-04-23T20:33:30.014998+08:00"},{"id":644,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:30.015593+08:00","gmt_modified":"2026-04-23T20:33:30.015593+08:00"},{"id":645,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:30.016186+08:00","gmt_modified":"2026-04-23T20:33:30.016187+08:00"},{"id":646,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:30.017118+08:00","gmt_modified":"2026-04-23T20:33:30.017118+08:00"},{"id":647,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-04-23T20:33:30.017481+08:00","gmt_modified":"2026-04-23T20:33:30.017481+08:00"},{"id":648,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:30.018279+08:00","gmt_modified":"2026-04-23T20:33:30.018279+08:00"},{"id":649,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T20:33:30.019076+08:00","gmt_modified":"2026-04-23T20:33:30.019076+08:00"},{"id":650,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T20:33:30.020384+08:00","gmt_modified":"2026-04-23T20:33:30.020384+08:00"},{"id":651,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"6e054d9a78c0c8c9da8dec4c4bda62ab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-28","gmt_create":"2026-04-23T20:33:30.021894+08:00","gmt_modified":"2026-04-23T20:33:30.021895+08:00"},{"id":652,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"6e054d9a78c0c8c9da8dec4c4bda62ab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-28","gmt_create":"2026-04-23T20:33:30.022319+08:00","gmt_modified":"2026-04-23T20:33:30.022319+08:00"},{"id":653,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:33:30.039084+08:00","gmt_modified":"2026-04-23T20:33:30.039085+08:00"},{"id":654,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:30.042279+08:00","gmt_modified":"2026-04-23T20:33:30.042279+08:00"},{"id":655,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:33:30.043781+08:00","gmt_modified":"2026-04-23T20:33:30.043781+08:00"},{"id":656,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-23T20:33:30.048591+08:00","gmt_modified":"2026-04-23T20:33:30.048591+08:00"},{"id":657,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:30.049875+08:00","gmt_modified":"2026-04-23T20:33:30.049875+08:00"},{"id":658,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T20:33:30.052505+08:00","gmt_modified":"2026-04-23T20:33:30.052505+08:00"},{"id":659,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T20:33:30.054452+08:00","gmt_modified":"2026-04-23T20:33:30.054452+08:00"},{"id":660,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"9c16a069e5154660bfdfa48f3518fc6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-38","gmt_create":"2026-04-23T20:33:30.056033+08:00","gmt_modified":"2026-04-23T20:33:30.056033+08:00"},{"id":661,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"9c16a069e5154660bfdfa48f3518fc6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-38","gmt_create":"2026-04-23T20:33:30.056759+08:00","gmt_modified":"2026-04-23T20:33:30.056759+08:00"},{"id":662,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"2d35e1345d25020f8e7ac1318db06f7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#30-90","gmt_create":"2026-04-23T20:33:30.060127+08:00","gmt_modified":"2026-04-23T20:33:30.060127+08:00"},{"id":663,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T20:33:30.06165+08:00","gmt_modified":"2026-04-23T20:33:30.06165+08:00"},{"id":664,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-48","gmt_create":"2026-04-23T20:33:30.063084+08:00","gmt_modified":"2026-04-23T20:33:30.063084+08:00"},{"id":665,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-48","gmt_create":"2026-04-23T20:33:30.063941+08:00","gmt_modified":"2026-04-23T20:33:30.063941+08:00"},{"id":666,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-48","gmt_create":"2026-04-23T20:33:30.065013+08:00","gmt_modified":"2026-04-23T20:33:30.065013+08:00"},{"id":667,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-48","gmt_create":"2026-04-23T20:33:30.066091+08:00","gmt_modified":"2026-04-23T20:33:30.066091+08:00"},{"id":668,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"72f6d334026866e8a61d2ffb1d83370a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-100","gmt_create":"2026-04-23T20:33:30.06977+08:00","gmt_modified":"2026-04-23T20:33:30.06977+08:00"},{"id":669,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"72f6d334026866e8a61d2ffb1d83370a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-100","gmt_create":"2026-04-23T20:33:30.070839+08:00","gmt_modified":"2026-04-23T20:33:30.070839+08:00"},{"id":670,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#122-146","gmt_create":"2026-04-23T20:33:30.07226+08:00","gmt_modified":"2026-04-23T20:33:30.07226+08:00"},{"id":671,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:33:30.076075+08:00","gmt_modified":"2026-04-23T20:33:30.076076+08:00"},{"id":672,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1e85186eded8743ff5f231df4aa6df3f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-48","gmt_create":"2026-04-23T20:33:30.080882+08:00","gmt_modified":"2026-04-23T20:33:30.080882+08:00"},{"id":673,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1d84b9a7eb013882953a2d1d948299e4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#126-197","gmt_create":"2026-04-23T20:33:30.082996+08:00","gmt_modified":"2026-04-23T20:33:30.082997+08:00"},{"id":674,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"1d84b9a7eb013882953a2d1d948299e4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 126-197","gmt_create":"2026-04-23T20:33:30.084021+08:00","gmt_modified":"2026-04-23T20:33:30.084021+08:00"},{"id":675,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e2b1718570fb714b2f4342221898ab30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-48","gmt_create":"2026-04-23T20:33:30.08518+08:00","gmt_modified":"2026-04-23T20:33:30.085181+08:00"},{"id":676,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ba687f2c64aff92b3906658359ed953a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#124-195","gmt_create":"2026-04-23T20:33:30.086912+08:00","gmt_modified":"2026-04-23T20:33:30.086913+08:00"},{"id":677,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"ba687f2c64aff92b3906658359ed953a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 124-195","gmt_create":"2026-04-23T20:33:30.087917+08:00","gmt_modified":"2026-04-23T20:33:30.087917+08:00"},{"id":678,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"52ee729b02c992c689522c7956c14128","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#57-62","gmt_create":"2026-04-23T20:33:30.090606+08:00","gmt_modified":"2026-04-23T20:33:30.090606+08:00"},{"id":679,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"52ee729b02c992c689522c7956c14128","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-62","gmt_create":"2026-04-23T20:33:30.092747+08:00","gmt_modified":"2026-04-23T20:33:30.092747+08:00"},{"id":680,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"c9e32b7324cce60c8887deb8404ee759","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#107-112","gmt_create":"2026-04-23T20:33:30.094246+08:00","gmt_modified":"2026-04-23T20:33:30.094246+08:00"},{"id":681,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"c9e32b7324cce60c8887deb8404ee759","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 107-112","gmt_create":"2026-04-23T20:33:30.095189+08:00","gmt_modified":"2026-04-23T20:33:30.095189+08:00"},{"id":682,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-04-23T20:33:30.096673+08:00","gmt_modified":"2026-04-23T20:33:30.096673+08:00"},{"id":683,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"8355d3821337334caee57a75dc8c8865","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#116-130","gmt_create":"2026-04-23T20:33:30.098422+08:00","gmt_modified":"2026-04-23T20:33:30.098422+08:00"},{"id":684,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"8355d3821337334caee57a75dc8c8865","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 116-130","gmt_create":"2026-04-23T20:33:30.099427+08:00","gmt_modified":"2026-04-23T20:33:30.099427+08:00"},{"id":685,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"4fe27d4d1323b500e72d870aa6212a1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#13-20","gmt_create":"2026-04-23T20:33:30.101771+08:00","gmt_modified":"2026-04-23T20:33:30.101771+08:00"},{"id":686,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"4fe27d4d1323b500e72d870aa6212a1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-20","gmt_create":"2026-04-23T20:33:30.102515+08:00","gmt_modified":"2026-04-23T20:33:30.102515+08:00"},{"id":687,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-157","gmt_create":"2026-04-23T20:33:30.103598+08:00","gmt_modified":"2026-04-23T20:33:30.103599+08:00"},{"id":688,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-157","gmt_create":"2026-04-23T20:33:30.104105+08:00","gmt_modified":"2026-04-23T20:33:30.104105+08:00"},{"id":689,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1ee5153c867fc6e9d277a3067963a1fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#32-38","gmt_create":"2026-04-23T20:33:30.105113+08:00","gmt_modified":"2026-04-23T20:33:30.105113+08:00"},{"id":690,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"1ee5153c867fc6e9d277a3067963a1fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-38","gmt_create":"2026-04-23T20:33:30.105627+08:00","gmt_modified":"2026-04-23T20:33:30.105627+08:00"},{"id":691,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#50-54","gmt_create":"2026-04-23T20:33:30.106672+08:00","gmt_modified":"2026-04-23T20:33:30.106672+08:00"},{"id":692,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 50-54","gmt_create":"2026-04-23T20:33:30.107651+08:00","gmt_modified":"2026-04-23T20:33:30.107651+08:00"},{"id":693,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"f6c9f1b4e8646c366a31426a4537675d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#36-38","gmt_create":"2026-04-23T20:33:30.109238+08:00","gmt_modified":"2026-04-23T20:33:30.109238+08:00"},{"id":694,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"1a3351698ecc7cd4e508b7a792804fc4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#302-309","gmt_create":"2026-04-23T20:33:30.111966+08:00","gmt_modified":"2026-04-23T20:33:30.111966+08:00"},{"id":695,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1a3351698ecc7cd4e508b7a792804fc4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 302-309","gmt_create":"2026-04-23T20:33:30.112959+08:00","gmt_modified":"2026-04-23T20:33:30.11296+08:00"},{"id":696,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"e3e9710c7eead933c936519395f792e0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#44-49","gmt_create":"2026-04-23T20:33:30.114604+08:00","gmt_modified":"2026-04-23T20:33:30.114605+08:00"},{"id":697,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"e3e9710c7eead933c936519395f792e0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-49","gmt_create":"2026-04-23T20:33:30.115247+08:00","gmt_modified":"2026-04-23T20:33:30.115247+08:00"},{"id":698,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7","gmt_create":"2026-04-23T20:33:30.116587+08:00","gmt_modified":"2026-04-23T20:33:30.116587+08:00"},{"id":699,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"a4143cc29b14f1f5bc75a5e021690666","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#23-31","gmt_create":"2026-04-23T20:33:30.117646+08:00","gmt_modified":"2026-04-23T20:33:30.117646+08:00"},{"id":700,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"a4143cc29b14f1f5bc75a5e021690666","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-31","gmt_create":"2026-04-23T20:33:30.118764+08:00","gmt_modified":"2026-04-23T20:33:30.118764+08:00"},{"id":701,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"7192cfda5508e7587efd91d26cf1f018","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#23-31","gmt_create":"2026-04-23T20:33:30.120253+08:00","gmt_modified":"2026-04-23T20:33:30.120253+08:00"},{"id":702,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"7192cfda5508e7587efd91d26cf1f018","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-31","gmt_create":"2026-04-23T20:33:30.121853+08:00","gmt_modified":"2026-04-23T20:33:30.121853+08:00"},{"id":703,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#211-227","gmt_create":"2026-04-23T20:33:30.1234+08:00","gmt_modified":"2026-04-23T20:33:30.1234+08:00"},{"id":704,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 211-227","gmt_create":"2026-04-23T20:33:30.125433+08:00","gmt_modified":"2026-04-23T20:33:30.125433+08:00"},{"id":705,"source_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","target_id":"fb5276346dcc4e7044d8765a8572e7a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-16","gmt_create":"2026-04-23T20:33:30.128657+08:00","gmt_modified":"2026-04-23T20:33:30.128657+08:00"},{"id":706,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"fb5276346dcc4e7044d8765a8572e7a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-16","gmt_create":"2026-04-23T20:33:30.129814+08:00","gmt_modified":"2026-04-23T20:33:30.129814+08:00"},{"id":707,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:37.259749+08:00","gmt_modified":"2026-04-23T20:33:37.259749+08:00"},{"id":708,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:37.26107+08:00","gmt_modified":"2026-04-23T20:33:37.26107+08:00"},{"id":709,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:37.261714+08:00","gmt_modified":"2026-04-23T20:33:37.261714+08:00"},{"id":710,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:37.262532+08:00","gmt_modified":"2026-04-23T20:33:37.262532+08:00"},{"id":711,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"e68ad5186f1e47610ab3d9f14a794393","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tongyi.py","gmt_create":"2026-04-23T20:33:37.263665+08:00","gmt_modified":"2026-04-23T20:33:37.263665+08:00"},{"id":712,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"404f6d0765a8c6e77e33b7fc21b377a4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/doubao.py","gmt_create":"2026-04-23T20:33:37.26425+08:00","gmt_modified":"2026-04-23T20:33:37.26425+08:00"},{"id":713,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"303e80519e946904d1cb3ac32cbb0814","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/qingyan.py","gmt_create":"2026-04-23T20:33:37.265278+08:00","gmt_modified":"2026-04-23T20:33:37.265278+08:00"},{"id":714,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5af7301fe056fc3d10820d820e8ad777","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/tiangong.py","gmt_create":"2026-04-23T20:33:37.265809+08:00","gmt_modified":"2026-04-23T20:33:37.265809+08:00"},{"id":715,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"0e38ad5d2d3daaad08c9302df8805b15","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/xinghuo.py","gmt_create":"2026-04-23T20:33:37.266496+08:00","gmt_modified":"2026-04-23T20:33:37.266496+08:00"},{"id":716,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:33:37.267203+08:00","gmt_modified":"2026-04-23T20:33:37.267203+08:00"},{"id":717,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:37.268722+08:00","gmt_modified":"2026-04-23T20:33:37.268722+08:00"},{"id":718,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:33:37.269288+08:00","gmt_modified":"2026-04-23T20:33:37.269288+08:00"},{"id":719,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:37.270139+08:00","gmt_modified":"2026-04-23T20:33:37.270139+08:00"},{"id":720,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:33:37.273632+08:00","gmt_modified":"2026-04-23T20:33:37.273632+08:00"},{"id":721,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:37.275218+08:00","gmt_modified":"2026-04-23T20:33:37.275218+08:00"},{"id":722,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:37.276269+08:00","gmt_modified":"2026-04-23T20:33:37.27627+08:00"},{"id":723,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-23T20:33:37.277294+08:00","gmt_modified":"2026-04-23T20:33:37.277294+08:00"},{"id":724,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:37.278423+08:00","gmt_modified":"2026-04-23T20:33:37.278423+08:00"},{"id":725,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-04-23T20:33:37.279079+08:00","gmt_modified":"2026-04-23T20:33:37.279079+08:00"},{"id":726,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-23T20:33:37.279629+08:00","gmt_modified":"2026-04-23T20:33:37.27963+08:00"},{"id":727,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-04-23T20:33:37.280454+08:00","gmt_modified":"2026-04-23T20:33:37.280454+08:00"},{"id":728,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:33:37.281512+08:00","gmt_modified":"2026-04-23T20:33:37.281513+08:00"},{"id":729,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"482d573f97b482b99bcde1c399eceb73","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-108","gmt_create":"2026-04-23T20:33:37.281875+08:00","gmt_modified":"2026-04-23T20:33:37.281876+08:00"},{"id":730,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"482d573f97b482b99bcde1c399eceb73","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 90-108","gmt_create":"2026-04-23T20:33:37.28285+08:00","gmt_modified":"2026-04-23T20:33:37.28285+08:00"},{"id":731,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-269","gmt_create":"2026-04-23T20:33:37.283208+08:00","gmt_modified":"2026-04-23T20:33:37.283208+08:00"},{"id":732,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:37.283598+08:00","gmt_modified":"2026-04-23T20:33:37.283598+08:00"},{"id":733,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4cef9e740b6feb68c6bd22b660c47320","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-123","gmt_create":"2026-04-23T20:33:37.284031+08:00","gmt_modified":"2026-04-23T20:33:37.284031+08:00"},{"id":734,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8d5aac2ae0671f05d7c0807ba9296cdf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-330","gmt_create":"2026-04-23T20:33:37.284881+08:00","gmt_modified":"2026-04-23T20:33:37.284881+08:00"},{"id":735,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:33:37.285439+08:00","gmt_modified":"2026-04-23T20:33:37.285439+08:00"},{"id":736,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"56f44cc97867cee3e5663424134d6072","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#1-37","gmt_create":"2026-04-23T20:33:37.285889+08:00","gmt_modified":"2026-04-23T20:33:37.285889+08:00"},{"id":737,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"56f44cc97867cee3e5663424134d6072","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:33:37.286195+08:00","gmt_modified":"2026-04-23T20:33:37.286195+08:00"},{"id":738,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"2e326ef8322619f1e8b3873022cb0437","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#1-37","gmt_create":"2026-04-23T20:33:37.286846+08:00","gmt_modified":"2026-04-23T20:33:37.286846+08:00"},{"id":739,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"2e326ef8322619f1e8b3873022cb0437","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:33:37.287299+08:00","gmt_modified":"2026-04-23T20:33:37.287299+08:00"},{"id":740,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"debd789847d1eed2d54198772edf68a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#1-38","gmt_create":"2026-04-23T20:33:37.28771+08:00","gmt_modified":"2026-04-23T20:33:37.287711+08:00"},{"id":741,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"3bde521d18cc7221ae2f14637e163aac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#1-38","gmt_create":"2026-04-23T20:33:37.288659+08:00","gmt_modified":"2026-04-23T20:33:37.288659+08:00"},{"id":742,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c26862d9e0fc878b51a2668cfd2ec827","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/qingyan.py#1-38","gmt_create":"2026-04-23T20:33:37.290497+08:00","gmt_modified":"2026-04-23T20:33:37.290498+08:00"},{"id":743,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"0fcc9c2e0d33b887c5f18a3807b64a1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tiangong.py#1-38","gmt_create":"2026-04-23T20:33:37.292345+08:00","gmt_modified":"2026-04-23T20:33:37.292345+08:00"},{"id":744,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"a4baa2444208b3f9a3f42bc492038207","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/xinghuo.py#1-38","gmt_create":"2026-04-23T20:33:37.293708+08:00","gmt_modified":"2026-04-23T20:33:37.293708+08:00"},{"id":745,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:33:37.2944+08:00","gmt_modified":"2026-04-23T20:33:37.2944+08:00"},{"id":746,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4cac57dbc530f0335c913ec5725dfa4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-121","gmt_create":"2026-04-23T20:33:37.295331+08:00","gmt_modified":"2026-04-23T20:33:37.295331+08:00"},{"id":747,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"4cac57dbc530f0335c913ec5725dfa4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-121","gmt_create":"2026-04-23T20:33:37.296239+08:00","gmt_modified":"2026-04-23T20:33:37.296239+08:00"},{"id":748,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:37.296858+08:00","gmt_modified":"2026-04-23T20:33:37.296858+08:00"},{"id":749,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:33:37.297624+08:00","gmt_modified":"2026-04-23T20:33:37.297624+08:00"},{"id":750,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:33:37.298765+08:00","gmt_modified":"2026-04-23T20:33:37.298765+08:00"},{"id":751,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-23T20:33:37.299752+08:00","gmt_modified":"2026-04-23T20:33:37.299752+08:00"},{"id":752,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:37.30067+08:00","gmt_modified":"2026-04-23T20:33:37.30067+08:00"},{"id":753,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"db174cfe219fc84d0dd26529f047b1d0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-330","gmt_create":"2026-04-23T20:33:37.304109+08:00","gmt_modified":"2026-04-23T20:33:37.304109+08:00"},{"id":754,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"db174cfe219fc84d0dd26529f047b1d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-330","gmt_create":"2026-04-23T20:33:37.304836+08:00","gmt_modified":"2026-04-23T20:33:37.304836+08:00"},{"id":755,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f36452f78aabfb0c46da03bbe25dff06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-295","gmt_create":"2026-04-23T20:33:37.307629+08:00","gmt_modified":"2026-04-23T20:33:37.307629+08:00"},{"id":756,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"f36452f78aabfb0c46da03bbe25dff06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-295","gmt_create":"2026-04-23T20:33:37.308258+08:00","gmt_modified":"2026-04-23T20:33:37.308258+08:00"},{"id":757,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"362d22f423631cda39404660b3317a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#177-254","gmt_create":"2026-04-23T20:33:37.310127+08:00","gmt_modified":"2026-04-23T20:33:37.310127+08:00"},{"id":758,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b475ff5225ac403c7fcf3dd7e14cbac6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#16-33","gmt_create":"2026-04-23T20:33:37.31061+08:00","gmt_modified":"2026-04-23T20:33:37.31061+08:00"},{"id":759,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:33:37.311106+08:00","gmt_modified":"2026-04-23T20:33:37.311106+08:00"},{"id":760,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-33","gmt_create":"2026-04-23T20:33:37.311558+08:00","gmt_modified":"2026-04-23T20:33:37.311558+08:00"},{"id":761,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-33","gmt_create":"2026-04-23T20:33:37.319146+08:00","gmt_modified":"2026-04-23T20:33:37.319146+08:00"},{"id":762,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"77158a6f887e224a03552893bfec7c92","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#16-33","gmt_create":"2026-04-23T20:33:37.320166+08:00","gmt_modified":"2026-04-23T20:33:37.320166+08:00"},{"id":763,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"9d352899554ab41b65b2e9f32558d811","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#39-113","gmt_create":"2026-04-23T20:33:37.321322+08:00","gmt_modified":"2026-04-23T20:33:37.321322+08:00"},{"id":764,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"9d352899554ab41b65b2e9f32558d811","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-113","gmt_create":"2026-04-23T20:33:37.322276+08:00","gmt_modified":"2026-04-23T20:33:37.322276+08:00"},{"id":765,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b1ee5a992230844ba898765be63f7b27","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#32-133","gmt_create":"2026-04-23T20:33:37.323119+08:00","gmt_modified":"2026-04-23T20:33:37.323119+08:00"},{"id":766,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"b1ee5a992230844ba898765be63f7b27","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-133","gmt_create":"2026-04-23T20:33:37.323615+08:00","gmt_modified":"2026-04-23T20:33:37.323615+08:00"},{"id":767,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"cb098a3cd32339e99f755dfd0fc35b5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#6-127","gmt_create":"2026-04-23T20:33:37.324259+08:00","gmt_modified":"2026-04-23T20:33:37.324259+08:00"},{"id":768,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"cb098a3cd32339e99f755dfd0fc35b5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-127","gmt_create":"2026-04-23T20:33:37.32508+08:00","gmt_modified":"2026-04-23T20:33:37.32508+08:00"},{"id":769,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#145-158","gmt_create":"2026-04-23T20:33:37.325915+08:00","gmt_modified":"2026-04-23T20:33:37.325915+08:00"},{"id":770,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"3d2dab79f7a3fedf24f0212cc9ef7aa1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 145-158","gmt_create":"2026-04-23T20:33:37.327012+08:00","gmt_modified":"2026-04-23T20:33:37.327012+08:00"},{"id":771,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4e9b3d0e94282f4bc6fa500f4eed61a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#135-159","gmt_create":"2026-04-23T20:33:37.327853+08:00","gmt_modified":"2026-04-23T20:33:37.327853+08:00"},{"id":772,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"4e9b3d0e94282f4bc6fa500f4eed61a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 135-159","gmt_create":"2026-04-23T20:33:37.328872+08:00","gmt_modified":"2026-04-23T20:33:37.328872+08:00"},{"id":773,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"8e3201561a9dd9a06ee3bf68ffdb3f99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#39-109","gmt_create":"2026-04-23T20:33:37.32989+08:00","gmt_modified":"2026-04-23T20:33:37.32989+08:00"},{"id":774,"source_id":"b07a4fb9cecbbd66a6910ccbc7651f19","target_id":"8e3201561a9dd9a06ee3bf68ffdb3f99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-109","gmt_create":"2026-04-23T20:33:37.33132+08:00","gmt_modified":"2026-04-23T20:33:37.33132+08:00"},{"id":775,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c3a417be3d61f5bcd3fbf976e0c4f15a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#33-121","gmt_create":"2026-04-23T20:33:37.336944+08:00","gmt_modified":"2026-04-23T20:33:37.336944+08:00"},{"id":776,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"c3a417be3d61f5bcd3fbf976e0c4f15a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-121","gmt_create":"2026-04-23T20:33:37.337655+08:00","gmt_modified":"2026-04-23T20:33:37.337655+08:00"},{"id":777,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:37.339169+08:00","gmt_modified":"2026-04-23T20:33:37.339169+08:00"},{"id":778,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7ce954ed7d3bc4dcf78630124cc0dd88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#264-295","gmt_create":"2026-04-23T20:33:37.34124+08:00","gmt_modified":"2026-04-23T20:33:37.34124+08:00"},{"id":779,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"7ce954ed7d3bc4dcf78630124cc0dd88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 264-295","gmt_create":"2026-04-23T20:33:37.342433+08:00","gmt_modified":"2026-04-23T20:33:37.342433+08:00"},{"id":780,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-35","gmt_create":"2026-04-23T20:33:37.346038+08:00","gmt_modified":"2026-04-23T20:33:37.346038+08:00"},{"id":781,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-35","gmt_create":"2026-04-23T20:33:37.346577+08:00","gmt_modified":"2026-04-23T20:33:37.346577+08:00"},{"id":782,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-32","gmt_create":"2026-04-23T20:33:37.352671+08:00","gmt_modified":"2026-04-23T20:33:37.352671+08:00"},{"id":783,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-32","gmt_create":"2026-04-23T20:33:37.354355+08:00","gmt_modified":"2026-04-23T20:33:37.354355+08:00"},{"id":784,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-32","gmt_create":"2026-04-23T20:33:37.355472+08:00","gmt_modified":"2026-04-23T20:33:37.355472+08:00"},{"id":785,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-32","gmt_create":"2026-04-23T20:33:37.357613+08:00","gmt_modified":"2026-04-23T20:33:37.357613+08:00"},{"id":786,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:33:37.358273+08:00","gmt_modified":"2026-04-23T20:33:37.358273+08:00"},{"id":787,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"5563b3bd56550648dc70302c1762ce5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/tongyi.py#18-29","gmt_create":"2026-04-23T20:33:37.360657+08:00","gmt_modified":"2026-04-23T20:33:37.360657+08:00"},{"id":788,"source_id":"e68ad5186f1e47610ab3d9f14a794393","target_id":"5563b3bd56550648dc70302c1762ce5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-29","gmt_create":"2026-04-23T20:33:37.361776+08:00","gmt_modified":"2026-04-23T20:33:37.361776+08:00"},{"id":789,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"91852ef8dcc844a2f85e9fce0227ab74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/doubao.py#18-29","gmt_create":"2026-04-23T20:33:37.363109+08:00","gmt_modified":"2026-04-23T20:33:37.363109+08:00"},{"id":790,"source_id":"404f6d0765a8c6e77e33b7fc21b377a4","target_id":"91852ef8dcc844a2f85e9fce0227ab74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-29","gmt_create":"2026-04-23T20:33:37.363811+08:00","gmt_modified":"2026-04-23T20:33:37.363811+08:00"},{"id":791,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"1b46fab9e22f53db30ead5677d03e3e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#11-16","gmt_create":"2026-04-23T20:33:37.364819+08:00","gmt_modified":"2026-04-23T20:33:37.364819+08:00"},{"id":792,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1b46fab9e22f53db30ead5677d03e3e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-16","gmt_create":"2026-04-23T20:33:37.365554+08:00","gmt_modified":"2026-04-23T20:33:37.365554+08:00"},{"id":793,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"f096aa3ea82e9fa625a9acb1309b4c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#231-247","gmt_create":"2026-04-23T20:33:37.36634+08:00","gmt_modified":"2026-04-23T20:33:37.366341+08:00"},{"id":794,"source_id":"19e75845-5147-4aeb-90be-16f3aa270465","target_id":"4a2fa09aa3a948dec5ef8ba873b0e716","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#14-42","gmt_create":"2026-04-23T20:33:37.367379+08:00","gmt_modified":"2026-04-23T20:33:37.367379+08:00"},{"id":795,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"4a2fa09aa3a948dec5ef8ba873b0e716","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-42","gmt_create":"2026-04-23T20:33:37.368233+08:00","gmt_modified":"2026-04-23T20:33:37.368233+08:00"},{"id":796,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:33:57.518077+08:00","gmt_modified":"2026-04-23T20:33:57.518077+08:00"},{"id":797,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-04-23T20:33:57.518453+08:00","gmt_modified":"2026-04-23T20:33:57.518454+08:00"},{"id":798,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-04-23T20:33:57.519644+08:00","gmt_modified":"2026-04-23T20:33:57.519644+08:00"},{"id":799,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:33:57.521079+08:00","gmt_modified":"2026-04-23T20:33:57.521079+08:00"},{"id":800,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:33:57.522061+08:00","gmt_modified":"2026-04-23T20:33:57.522061+08:00"},{"id":801,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:33:57.523189+08:00","gmt_modified":"2026-04-23T20:33:57.523189+08:00"},{"id":802,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-23T20:33:57.52383+08:00","gmt_modified":"2026-04-23T20:33:57.52383+08:00"},{"id":803,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:33:57.524563+08:00","gmt_modified":"2026-04-23T20:33:57.524563+08:00"},{"id":804,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:33:57.525774+08:00","gmt_modified":"2026-04-23T20:33:57.525774+08:00"},{"id":805,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:33:57.526492+08:00","gmt_modified":"2026-04-23T20:33:57.526492+08:00"},{"id":806,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:33:57.527326+08:00","gmt_modified":"2026-04-23T20:33:57.527326+08:00"},{"id":807,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:33:57.527983+08:00","gmt_modified":"2026-04-23T20:33:57.527983+08:00"},{"id":808,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:33:57.529144+08:00","gmt_modified":"2026-04-23T20:33:57.529144+08:00"},{"id":809,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-23T20:33:57.529998+08:00","gmt_modified":"2026-04-23T20:33:57.529998+08:00"},{"id":810,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:33:57.530659+08:00","gmt_modified":"2026-04-23T20:33:57.530659+08:00"},{"id":811,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:33:57.531953+08:00","gmt_modified":"2026-04-23T20:33:57.531953+08:00"},{"id":812,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-04-23T20:33:57.532681+08:00","gmt_modified":"2026-04-23T20:33:57.532681+08:00"},{"id":813,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"80a0429cc47931de27ddb17a62b8dd9c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_business_flow.py","gmt_create":"2026-04-23T20:33:57.533708+08:00","gmt_modified":"2026-04-23T20:33:57.533708+08:00"},{"id":814,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e27bcba24aaadeec1922d2b4e5b8386b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-109","gmt_create":"2026-04-23T20:33:57.534482+08:00","gmt_modified":"2026-04-23T20:33:57.534482+08:00"},{"id":815,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e7afbab5932c93c3469f1a225e6c7156","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-55","gmt_create":"2026-04-23T20:33:57.535515+08:00","gmt_modified":"2026-04-23T20:33:57.535515+08:00"},{"id":816,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"e7afbab5932c93c3469f1a225e6c7156","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-55","gmt_create":"2026-04-23T20:33:57.536318+08:00","gmt_modified":"2026-04-23T20:33:57.536318+08:00"},{"id":817,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a0eac56d622a2fff529bc2b796064bcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#1-94","gmt_create":"2026-04-23T20:33:57.537094+08:00","gmt_modified":"2026-04-23T20:33:57.537094+08:00"},{"id":818,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"a0eac56d622a2fff529bc2b796064bcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-94","gmt_create":"2026-04-23T20:33:57.537769+08:00","gmt_modified":"2026-04-23T20:33:57.53777+08:00"},{"id":819,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"174be58163b6f72b4cd4a493f3463ce4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#1-52","gmt_create":"2026-04-23T20:33:57.53855+08:00","gmt_modified":"2026-04-23T20:33:57.53855+08:00"},{"id":820,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"174be58163b6f72b4cd4a493f3463ce4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-52","gmt_create":"2026-04-23T20:33:57.53965+08:00","gmt_modified":"2026-04-23T20:33:57.53965+08:00"},{"id":821,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-23T20:33:57.54057+08:00","gmt_modified":"2026-04-23T20:33:57.54057+08:00"},{"id":822,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-04-23T20:33:57.541654+08:00","gmt_modified":"2026-04-23T20:33:57.541654+08:00"},{"id":823,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-23T20:33:57.543056+08:00","gmt_modified":"2026-04-23T20:33:57.543056+08:00"},{"id":824,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-04-23T20:33:57.543958+08:00","gmt_modified":"2026-04-23T20:33:57.543958+08:00"},{"id":825,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-23T20:33:57.544974+08:00","gmt_modified":"2026-04-23T20:33:57.544974+08:00"},{"id":826,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-130","gmt_create":"2026-04-23T20:33:57.545482+08:00","gmt_modified":"2026-04-23T20:33:57.545482+08:00"},{"id":827,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-130","gmt_create":"2026-04-23T20:33:57.545785+08:00","gmt_modified":"2026-04-23T20:33:57.545785+08:00"},{"id":828,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-429","gmt_create":"2026-04-23T20:33:57.546196+08:00","gmt_modified":"2026-04-23T20:33:57.546196+08:00"},{"id":829,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-429","gmt_create":"2026-04-23T20:33:57.546517+08:00","gmt_modified":"2026-04-23T20:33:57.546517+08:00"},{"id":830,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-23T20:33:57.547004+08:00","gmt_modified":"2026-04-23T20:33:57.547005+08:00"},{"id":831,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-23T20:33:57.5475+08:00","gmt_modified":"2026-04-23T20:33:57.5475+08:00"},{"id":832,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-23T20:33:57.548046+08:00","gmt_modified":"2026-04-23T20:33:57.548046+08:00"},{"id":833,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"39a3b2d9301fa4eff7bef0fda3352790","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#1-206","gmt_create":"2026-04-23T20:33:57.548538+08:00","gmt_modified":"2026-04-23T20:33:57.548538+08:00"},{"id":834,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"39a3b2d9301fa4eff7bef0fda3352790","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-206","gmt_create":"2026-04-23T20:33:57.548868+08:00","gmt_modified":"2026-04-23T20:33:57.548868+08:00"},{"id":835,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fbcfae3b1238b3da5329ebafe4294861","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#1-205","gmt_create":"2026-04-23T20:33:57.549268+08:00","gmt_modified":"2026-04-23T20:33:57.549268+08:00"},{"id":836,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"fbcfae3b1238b3da5329ebafe4294861","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-205","gmt_create":"2026-04-23T20:33:57.549553+08:00","gmt_modified":"2026-04-23T20:33:57.549553+08:00"},{"id":837,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-23T20:33:57.550006+08:00","gmt_modified":"2026-04-23T20:33:57.550006+08:00"},{"id":838,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c4273407c88f470df7daf6a8ad5ce969","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-109","gmt_create":"2026-04-23T20:33:57.550496+08:00","gmt_modified":"2026-04-23T20:33:57.550496+08:00"},{"id":839,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c4273407c88f470df7daf6a8ad5ce969","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15-109","gmt_create":"2026-04-23T20:33:57.551777+08:00","gmt_modified":"2026-04-23T20:33:57.551777+08:00"},{"id":840,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"35774e0a09ac5459c868914d7182ca95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#19-55","gmt_create":"2026-04-23T20:33:57.552775+08:00","gmt_modified":"2026-04-23T20:33:57.552775+08:00"},{"id":841,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"35774e0a09ac5459c868914d7182ca95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-55","gmt_create":"2026-04-23T20:33:57.553082+08:00","gmt_modified":"2026-04-23T20:33:57.553082+08:00"},{"id":842,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-04-23T20:33:57.553571+08:00","gmt_modified":"2026-04-23T20:33:57.553571+08:00"},{"id":843,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"f639b566c26dfd18b24e3dfd2e9853ac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-52","gmt_create":"2026-04-23T20:33:57.554164+08:00","gmt_modified":"2026-04-23T20:33:57.554164+08:00"},{"id":844,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"f639b566c26dfd18b24e3dfd2e9853ac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-52","gmt_create":"2026-04-23T20:33:57.554458+08:00","gmt_modified":"2026-04-23T20:33:57.554458+08:00"},{"id":845,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:33:57.55511+08:00","gmt_modified":"2026-04-23T20:33:57.55511+08:00"},{"id":846,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:33:57.557064+08:00","gmt_modified":"2026-04-23T20:33:57.557064+08:00"},{"id":847,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:33:57.558255+08:00","gmt_modified":"2026-04-23T20:33:57.558255+08:00"},{"id":848,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-04-23T20:33:57.558894+08:00","gmt_modified":"2026-04-23T20:33:57.558894+08:00"},{"id":849,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T20:33:57.560321+08:00","gmt_modified":"2026-04-23T20:33:57.560321+08:00"},{"id":850,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b46654006178160f12897e2c5baac8fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-429","gmt_create":"2026-04-23T20:33:57.561417+08:00","gmt_modified":"2026-04-23T20:33:57.561417+08:00"},{"id":851,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"b46654006178160f12897e2c5baac8fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-429","gmt_create":"2026-04-23T20:33:57.561724+08:00","gmt_modified":"2026-04-23T20:33:57.561724+08:00"},{"id":852,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-04-23T20:33:57.562679+08:00","gmt_modified":"2026-04-23T20:33:57.562679+08:00"},{"id":853,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-04-23T20:33:57.563303+08:00","gmt_modified":"2026-04-23T20:33:57.563303+08:00"},{"id":854,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ad67863041d9eea2b0fb542b5aa33aca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#4-18","gmt_create":"2026-04-23T20:33:57.563842+08:00","gmt_modified":"2026-04-23T20:33:57.563842+08:00"},{"id":855,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"82265d393c20d0af96beec6b9c657c27","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#28-41","gmt_create":"2026-04-23T20:33:57.564486+08:00","gmt_modified":"2026-04-23T20:33:57.564486+08:00"},{"id":856,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"82265d393c20d0af96beec6b9c657c27","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-41","gmt_create":"2026-04-23T20:33:57.564788+08:00","gmt_modified":"2026-04-23T20:33:57.564788+08:00"},{"id":857,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c86edb7a95fbe4b431ac65a0e2b8636e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#90-109","gmt_create":"2026-04-23T20:33:57.565285+08:00","gmt_modified":"2026-04-23T20:33:57.565285+08:00"},{"id":858,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-23T20:33:57.565809+08:00","gmt_modified":"2026-04-23T20:33:57.565809+08:00"},{"id":859,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"93e5c95b1691bb81a36bf9a0ac889030","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-261","gmt_create":"2026-04-23T20:33:57.566399+08:00","gmt_modified":"2026-04-23T20:33:57.566399+08:00"},{"id":860,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"93e5c95b1691bb81a36bf9a0ac889030","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-261","gmt_create":"2026-04-23T20:33:57.578474+08:00","gmt_modified":"2026-04-23T20:33:57.578474+08:00"},{"id":861,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:33:57.580464+08:00","gmt_modified":"2026-04-23T20:33:57.580464+08:00"},{"id":862,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-04-23T20:33:57.581421+08:00","gmt_modified":"2026-04-23T20:33:57.581422+08:00"},{"id":863,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"a4918fcbd21492ad996d7f5496f03a4b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#33-48","gmt_create":"2026-04-23T20:33:57.58279+08:00","gmt_modified":"2026-04-23T20:33:57.58279+08:00"},{"id":864,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"bc38d046b4b1410ae2165cee2272839e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#33-48","gmt_create":"2026-04-23T20:33:57.583676+08:00","gmt_modified":"2026-04-23T20:33:57.583676+08:00"},{"id":865,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"374200f0bf946f0399351756977d0495","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#176-234","gmt_create":"2026-04-23T20:33:57.588601+08:00","gmt_modified":"2026-04-23T20:33:57.588601+08:00"},{"id":866,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"374200f0bf946f0399351756977d0495","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 176-234","gmt_create":"2026-04-23T20:33:57.589609+08:00","gmt_modified":"2026-04-23T20:33:57.589609+08:00"},{"id":867,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ac5982063da5f04315f3e82a0d653902","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#24-32","gmt_create":"2026-04-23T20:33:57.590732+08:00","gmt_modified":"2026-04-23T20:33:57.590732+08:00"},{"id":868,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"601b981b00d93b941843f046a163d5a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#18-33","gmt_create":"2026-04-23T20:33:57.592508+08:00","gmt_modified":"2026-04-23T20:33:57.592508+08:00"},{"id":869,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"9a8d9100a6bc34ebae9ee065def7e88a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#44-72","gmt_create":"2026-04-23T20:33:57.593647+08:00","gmt_modified":"2026-04-23T20:33:57.593647+08:00"},{"id":870,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"9a8d9100a6bc34ebae9ee065def7e88a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-72","gmt_create":"2026-04-23T20:33:57.594757+08:00","gmt_modified":"2026-04-23T20:33:57.594757+08:00"},{"id":871,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"93c23bcc3456826af17e26a6d4c32116","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#6-9","gmt_create":"2026-04-23T20:33:57.595474+08:00","gmt_modified":"2026-04-23T20:33:57.595474+08:00"},{"id":872,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"93c23bcc3456826af17e26a6d4c32116","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-9","gmt_create":"2026-04-23T20:33:57.596276+08:00","gmt_modified":"2026-04-23T20:33:57.596276+08:00"},{"id":873,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c17eeb8726297096cd5542283f11494f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#17-109","gmt_create":"2026-04-23T20:33:57.597516+08:00","gmt_modified":"2026-04-23T20:33:57.597516+08:00"},{"id":874,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"c17eeb8726297096cd5542283f11494f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-109","gmt_create":"2026-04-23T20:33:57.598386+08:00","gmt_modified":"2026-04-23T20:33:57.598386+08:00"},{"id":875,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"08fec4718be6991260c00ca532f9173a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#22-55","gmt_create":"2026-04-23T20:33:57.599188+08:00","gmt_modified":"2026-04-23T20:33:57.599188+08:00"},{"id":876,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"08fec4718be6991260c00ca532f9173a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-55","gmt_create":"2026-04-23T20:33:57.600043+08:00","gmt_modified":"2026-04-23T20:33:57.600043+08:00"},{"id":877,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"08007199eea846dd14f15f7dc70419e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#48-52","gmt_create":"2026-04-23T20:33:57.600852+08:00","gmt_modified":"2026-04-23T20:33:57.600852+08:00"},{"id":878,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"08007199eea846dd14f15f7dc70419e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-52","gmt_create":"2026-04-23T20:33:57.601489+08:00","gmt_modified":"2026-04-23T20:33:57.601489+08:00"},{"id":879,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"4caff756fd4da029bd64cd16e7ef5960","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#32-39","gmt_create":"2026-04-23T20:33:57.602322+08:00","gmt_modified":"2026-04-23T20:33:57.602323+08:00"},{"id":880,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"4caff756fd4da029bd64cd16e7ef5960","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-39","gmt_create":"2026-04-23T20:33:57.602918+08:00","gmt_modified":"2026-04-23T20:33:57.602918+08:00"},{"id":881,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b0220895f66f1273966ad5b2c3266952","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#49-53","gmt_create":"2026-04-23T20:33:57.603881+08:00","gmt_modified":"2026-04-23T20:33:57.603881+08:00"},{"id":882,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"b0220895f66f1273966ad5b2c3266952","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-53","gmt_create":"2026-04-23T20:33:57.604555+08:00","gmt_modified":"2026-04-23T20:33:57.604555+08:00"},{"id":883,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"44f88f9664fdf6e84ffb7e0675a86a28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#64-69","gmt_create":"2026-04-23T20:33:57.605262+08:00","gmt_modified":"2026-04-23T20:33:57.605262+08:00"},{"id":884,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"44f88f9664fdf6e84ffb7e0675a86a28","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 64-69","gmt_create":"2026-04-23T20:33:57.606324+08:00","gmt_modified":"2026-04-23T20:33:57.606324+08:00"},{"id":885,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"91f280f51389bd1cf711dcf33a4da681","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#79-84","gmt_create":"2026-04-23T20:33:57.607055+08:00","gmt_modified":"2026-04-23T20:33:57.607055+08:00"},{"id":886,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"91f280f51389bd1cf711dcf33a4da681","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-84","gmt_create":"2026-04-23T20:33:57.608388+08:00","gmt_modified":"2026-04-23T20:33:57.608388+08:00"},{"id":887,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ab50466a57c77659d7b469d3a8a04ddb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#96-103","gmt_create":"2026-04-23T20:33:57.609206+08:00","gmt_modified":"2026-04-23T20:33:57.609206+08:00"},{"id":888,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"ab50466a57c77659d7b469d3a8a04ddb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 96-103","gmt_create":"2026-04-23T20:33:57.609975+08:00","gmt_modified":"2026-04-23T20:33:57.609975+08:00"},{"id":889,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#65-71","gmt_create":"2026-04-23T20:33:57.61104+08:00","gmt_modified":"2026-04-23T20:33:57.611041+08:00"},{"id":890,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"572c2dece1fbc13aa2bb7d6b61b0fd5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-71","gmt_create":"2026-04-23T20:33:57.611833+08:00","gmt_modified":"2026-04-23T20:33:57.611833+08:00"},{"id":891,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"82386bc7ca57d9ccc94b656e52bc89f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-14","gmt_create":"2026-04-23T20:33:57.612865+08:00","gmt_modified":"2026-04-23T20:33:57.612865+08:00"},{"id":892,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"82386bc7ca57d9ccc94b656e52bc89f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-04-23T20:33:57.613537+08:00","gmt_modified":"2026-04-23T20:33:57.613537+08:00"},{"id":893,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"7ab79ab21d7d6e4dbcb224572516f6f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-19","gmt_create":"2026-04-23T20:33:57.613967+08:00","gmt_modified":"2026-04-23T20:33:57.613968+08:00"},{"id":894,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"7ab79ab21d7d6e4dbcb224572516f6f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-19","gmt_create":"2026-04-23T20:33:57.61426+08:00","gmt_modified":"2026-04-23T20:33:57.61426+08:00"},{"id":895,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"8433204d7a82a1f480e57df9ceee5581","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-10","gmt_create":"2026-04-23T20:33:57.614658+08:00","gmt_modified":"2026-04-23T20:33:57.614658+08:00"},{"id":896,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"8433204d7a82a1f480e57df9ceee5581","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-23T20:33:57.614988+08:00","gmt_modified":"2026-04-23T20:33:57.614988+08:00"},{"id":897,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"3957ee6f15a01b7b541490438ef18684","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-17","gmt_create":"2026-04-23T20:33:57.615388+08:00","gmt_modified":"2026-04-23T20:33:57.615388+08:00"},{"id":898,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"3957ee6f15a01b7b541490438ef18684","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-17","gmt_create":"2026-04-23T20:33:57.615908+08:00","gmt_modified":"2026-04-23T20:33:57.615908+08:00"},{"id":899,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"3729543092bccad8926c5ea852db1e69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-157","gmt_create":"2026-04-23T20:33:57.61673+08:00","gmt_modified":"2026-04-23T20:33:57.61673+08:00"},{"id":900,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fcae8d1d281ad7186999cc4ca8e43db7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-39","gmt_create":"2026-04-23T20:33:57.617716+08:00","gmt_modified":"2026-04-23T20:33:57.617716+08:00"},{"id":901,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"fcae8d1d281ad7186999cc4ca8e43db7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-39","gmt_create":"2026-04-23T20:33:57.618148+08:00","gmt_modified":"2026-04-23T20:33:57.618148+08:00"},{"id":902,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ee12a84ac6334b13e20132181454488b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#13-19","gmt_create":"2026-04-23T20:33:57.6192+08:00","gmt_modified":"2026-04-23T20:33:57.6192+08:00"},{"id":903,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"ee12a84ac6334b13e20132181454488b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-19","gmt_create":"2026-04-23T20:33:57.619587+08:00","gmt_modified":"2026-04-23T20:33:57.619587+08:00"},{"id":904,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"897e047b94772e5a0ff57cf773a7f965","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#17-32","gmt_create":"2026-04-23T20:33:57.620024+08:00","gmt_modified":"2026-04-23T20:33:57.620024+08:00"},{"id":905,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"897e047b94772e5a0ff57cf773a7f965","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-32","gmt_create":"2026-04-23T20:33:57.620315+08:00","gmt_modified":"2026-04-23T20:33:57.620315+08:00"},{"id":906,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"53e8ec81b4d2dbb13c831048e5897036","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#17-32","gmt_create":"2026-04-23T20:33:57.620909+08:00","gmt_modified":"2026-04-23T20:33:57.620909+08:00"},{"id":907,"source_id":"f642fc1c2f34e15572d9d98aa6c18813","target_id":"53e8ec81b4d2dbb13c831048e5897036","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-32","gmt_create":"2026-04-23T20:33:57.621267+08:00","gmt_modified":"2026-04-23T20:33:57.621267+08:00"},{"id":908,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:33:57.621687+08:00","gmt_modified":"2026-04-23T20:33:57.621687+08:00"},{"id":909,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"ef82ce4377c549013c200e19701a6805","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#21-32","gmt_create":"2026-04-23T20:33:57.62216+08:00","gmt_modified":"2026-04-23T20:33:57.62216+08:00"},{"id":910,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"c7986eb1be0ffdd9ec4e243be4270119","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#21-32","gmt_create":"2026-04-23T20:33:57.623241+08:00","gmt_modified":"2026-04-23T20:33:57.623241+08:00"},{"id":911,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"eecf9581dbaa0a515cf11514175e7ef9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#11-206","gmt_create":"2026-04-23T20:33:57.627555+08:00","gmt_modified":"2026-04-23T20:33:57.627555+08:00"},{"id":912,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"5563c29185326a59be61ee0a6eec4463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#11-205","gmt_create":"2026-04-23T20:33:57.62809+08:00","gmt_modified":"2026-04-23T20:33:57.62809+08:00"},{"id":913,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"fd3145047b9c813cc8e64b9322e531f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#219-327","gmt_create":"2026-04-23T20:33:57.62931+08:00","gmt_modified":"2026-04-23T20:33:57.62931+08:00"},{"id":914,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"fd3145047b9c813cc8e64b9322e531f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 219-327","gmt_create":"2026-04-23T20:33:57.629745+08:00","gmt_modified":"2026-04-23T20:33:57.629745+08:00"},{"id":915,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"b09a0f415030d91b25e6cabd8a0a93fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#176-289","gmt_create":"2026-04-23T20:33:57.630458+08:00","gmt_modified":"2026-04-23T20:33:57.630458+08:00"},{"id":916,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"b09a0f415030d91b25e6cabd8a0a93fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 176-289","gmt_create":"2026-04-23T20:33:57.630748+08:00","gmt_modified":"2026-04-23T20:33:57.630748+08:00"},{"id":917,"source_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","target_id":"e2168959b26c386940370b5f1bf48d7d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#194-204","gmt_create":"2026-04-23T20:33:57.631184+08:00","gmt_modified":"2026-04-23T20:33:57.631184+08:00"},{"id":918,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"e2168959b26c386940370b5f1bf48d7d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 194-204","gmt_create":"2026-04-23T20:33:57.63147+08:00","gmt_modified":"2026-04-23T20:33:57.63147+08:00"},{"id":919,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-23T20:35:18.634061+08:00","gmt_modified":"2026-04-23T20:35:18.634062+08:00"},{"id":920,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-23T20:35:18.634886+08:00","gmt_modified":"2026-04-23T20:35:18.634886+08:00"},{"id":921,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"6a63f048c16c60c5d2d57012c810ee0e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/search_engine.py","gmt_create":"2026-04-23T20:35:18.635377+08:00","gmt_modified":"2026-04-23T20:35:18.635377+08:00"},{"id":922,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4a56ef5fca60bc63480b457cab3832f0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/__init__.py","gmt_create":"2026-04-23T20:35:18.63595+08:00","gmt_modified":"2026-04-23T20:35:18.63595+08:00"},{"id":923,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-23T20:35:18.636363+08:00","gmt_modified":"2026-04-23T20:35:18.636363+08:00"},{"id":924,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-23T20:35:18.636753+08:00","gmt_modified":"2026-04-23T20:35:18.636753+08:00"},{"id":925,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"36dd0ad3ee6bc75a480ad8a62268e80e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/models/query.py","gmt_create":"2026-04-23T20:35:18.6372+08:00","gmt_modified":"2026-04-23T20:35:18.6372+08:00"},{"id":926,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-23T20:35:18.637558+08:00","gmt_modified":"2026-04-23T20:35:18.637558+08:00"},{"id":927,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-04-23T20:35:18.637924+08:00","gmt_modified":"2026-04-23T20:35:18.637924+08:00"},{"id":928,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-04-23T20:35:18.638407+08:00","gmt_modified":"2026-04-23T20:35:18.638407+08:00"},{"id":929,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-04-23T20:35:18.638942+08:00","gmt_modified":"2026-04-23T20:35:18.638942+08:00"},{"id":930,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-23T20:35:18.641162+08:00","gmt_modified":"2026-04-23T20:35:18.641162+08:00"},{"id":931,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-04-23T20:35:18.642251+08:00","gmt_modified":"2026-04-23T20:35:18.642251+08:00"},{"id":932,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-23T20:35:18.642925+08:00","gmt_modified":"2026-04-23T20:35:18.642925+08:00"},{"id":933,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-23T20:35:18.643414+08:00","gmt_modified":"2026-04-23T20:35:18.643415+08:00"},{"id":934,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-04-23T20:35:18.643912+08:00","gmt_modified":"2026-04-23T20:35:18.643912+08:00"},{"id":935,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"129573d2bbcde48697ed0e75dea12396","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-40","gmt_create":"2026-04-23T20:35:18.645078+08:00","gmt_modified":"2026-04-23T20:35:18.645078+08:00"},{"id":936,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"129573d2bbcde48697ed0e75dea12396","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-40","gmt_create":"2026-04-23T20:35:18.646964+08:00","gmt_modified":"2026-04-23T20:35:18.646965+08:00"},{"id":937,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"cf18c97a9be6c78aa43cc229ed3dad20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#164-173","gmt_create":"2026-04-23T20:35:18.647598+08:00","gmt_modified":"2026-04-23T20:35:18.647598+08:00"},{"id":938,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"cf18c97a9be6c78aa43cc229ed3dad20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 164-173","gmt_create":"2026-04-23T20:35:18.647972+08:00","gmt_modified":"2026-04-23T20:35:18.647972+08:00"},{"id":939,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"3c7ca5d582dca31c2530b1ce9c058e95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#10-37","gmt_create":"2026-04-23T20:35:18.648459+08:00","gmt_modified":"2026-04-23T20:35:18.64846+08:00"},{"id":940,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"3c7ca5d582dca31c2530b1ce9c058e95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-37","gmt_create":"2026-04-23T20:35:18.648785+08:00","gmt_modified":"2026-04-23T20:35:18.648785+08:00"},{"id":941,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9f82f6d82bf914a608d6afa3d9854abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#1-174","gmt_create":"2026-04-23T20:35:18.649264+08:00","gmt_modified":"2026-04-23T20:35:18.649264+08:00"},{"id":942,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-23T20:35:18.650358+08:00","gmt_modified":"2026-04-23T20:35:18.650358+08:00"},{"id":943,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-04-23T20:35:18.650954+08:00","gmt_modified":"2026-04-23T20:35:18.650954+08:00"},{"id":944,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-04-23T20:35:18.652232+08:00","gmt_modified":"2026-04-23T20:35:18.652232+08:00"},{"id":945,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-04-23T20:35:18.653511+08:00","gmt_modified":"2026-04-23T20:35:18.653511+08:00"},{"id":946,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"27047f868643e5457d4f242b4298a9f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-23","gmt_create":"2026-04-23T20:35:18.654994+08:00","gmt_modified":"2026-04-23T20:35:18.654994+08:00"},{"id":947,"source_id":"ef72f0c3cedb9fd9a87352fe493053dc","target_id":"27047f868643e5457d4f242b4298a9f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-23","gmt_create":"2026-04-23T20:35:18.6556+08:00","gmt_modified":"2026-04-23T20:35:18.6556+08:00"},{"id":948,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"557ae34b57a5dd8e8fa3bb2a6ce178a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#163-174","gmt_create":"2026-04-23T20:35:18.657485+08:00","gmt_modified":"2026-04-23T20:35:18.657486+08:00"},{"id":949,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"1526e4e02133a48eac04befb74ec5bd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#161-173","gmt_create":"2026-04-23T20:35:18.65887+08:00","gmt_modified":"2026-04-23T20:35:18.65887+08:00"},{"id":950,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"1526e4e02133a48eac04befb74ec5bd1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-173","gmt_create":"2026-04-23T20:35:18.659265+08:00","gmt_modified":"2026-04-23T20:35:18.659265+08:00"},{"id":951,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#26-39","gmt_create":"2026-04-23T20:35:18.661103+08:00","gmt_modified":"2026-04-23T20:35:18.661103+08:00"},{"id":952,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-39","gmt_create":"2026-04-23T20:35:18.661433+08:00","gmt_modified":"2026-04-23T20:35:18.661433+08:00"},{"id":953,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-04-23T20:35:18.661922+08:00","gmt_modified":"2026-04-23T20:35:18.661922+08:00"},{"id":954,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-04-23T20:35:18.662781+08:00","gmt_modified":"2026-04-23T20:35:18.662781+08:00"},{"id":955,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-234","gmt_create":"2026-04-23T20:35:18.680675+08:00","gmt_modified":"2026-04-23T20:35:18.680675+08:00"},{"id":956,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"448970b02d89d5e1576f70bdb0063363","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-84","gmt_create":"2026-04-23T20:35:18.68314+08:00","gmt_modified":"2026-04-23T20:35:18.68314+08:00"},{"id":957,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8565f299083b4dcba5a328c947f06fee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#256-287","gmt_create":"2026-04-23T20:35:18.685341+08:00","gmt_modified":"2026-04-23T20:35:18.685341+08:00"},{"id":958,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"52c01d7b9c17aa16944cbfcf8885be61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-33","gmt_create":"2026-04-23T20:35:18.686894+08:00","gmt_modified":"2026-04-23T20:35:18.686894+08:00"},{"id":959,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"2a971cb83924013902324eceeab22559","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#16-29","gmt_create":"2026-04-23T20:35:18.689849+08:00","gmt_modified":"2026-04-23T20:35:18.689849+08:00"},{"id":960,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"2a971cb83924013902324eceeab22559","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-29","gmt_create":"2026-04-23T20:35:18.69154+08:00","gmt_modified":"2026-04-23T20:35:18.69154+08:00"},{"id":961,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"99326fedad9275392719105b5b6782d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#31-33","gmt_create":"2026-04-23T20:35:18.692776+08:00","gmt_modified":"2026-04-23T20:35:18.692776+08:00"},{"id":962,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"99326fedad9275392719105b5b6782d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-33","gmt_create":"2026-04-23T20:35:18.693945+08:00","gmt_modified":"2026-04-23T20:35:18.693945+08:00"},{"id":963,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"102223dd13475177a1ade8b9be14fbd1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#79-144","gmt_create":"2026-04-23T20:35:18.695323+08:00","gmt_modified":"2026-04-23T20:35:18.695324+08:00"},{"id":964,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5e5dacc623918c0f1eba234154c99291","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#16-76","gmt_create":"2026-04-23T20:35:18.696341+08:00","gmt_modified":"2026-04-23T20:35:18.696341+08:00"},{"id":965,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"5e5dacc623918c0f1eba234154c99291","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-76","gmt_create":"2026-04-23T20:35:18.697266+08:00","gmt_modified":"2026-04-23T20:35:18.697267+08:00"},{"id":966,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"5be7e6cf82d6359efddaf131aaf92615","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#323-330","gmt_create":"2026-04-23T20:35:18.701473+08:00","gmt_modified":"2026-04-23T20:35:18.701473+08:00"},{"id":967,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"5be7e6cf82d6359efddaf131aaf92615","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 323-330","gmt_create":"2026-04-23T20:35:18.7021+08:00","gmt_modified":"2026-04-23T20:35:18.7021+08:00"},{"id":968,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#86-90","gmt_create":"2026-04-23T20:35:18.703871+08:00","gmt_modified":"2026-04-23T20:35:18.703871+08:00"},{"id":969,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-90","gmt_create":"2026-04-23T20:35:18.709231+08:00","gmt_modified":"2026-04-23T20:35:18.709231+08:00"},{"id":970,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-04-23T20:35:18.712574+08:00","gmt_modified":"2026-04-23T20:35:18.712574+08:00"},{"id":971,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-77","gmt_create":"2026-04-23T20:35:18.713529+08:00","gmt_modified":"2026-04-23T20:35:18.713529+08:00"},{"id":972,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"d7c319a04abbc6704da53107e07dd8e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-130","gmt_create":"2026-04-23T20:35:18.714412+08:00","gmt_modified":"2026-04-23T20:35:18.714412+08:00"},{"id":973,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"d780e807ee751f39f331a658b47c4ed3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#24-269","gmt_create":"2026-04-23T20:35:18.715261+08:00","gmt_modified":"2026-04-23T20:35:18.715261+08:00"},{"id":974,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"d780e807ee751f39f331a658b47c4ed3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-269","gmt_create":"2026-04-23T20:35:18.716135+08:00","gmt_modified":"2026-04-23T20:35:18.716135+08:00"},{"id":975,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8eea43550951387ac740b5e3e64c7691","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#94-96","gmt_create":"2026-04-23T20:35:18.720519+08:00","gmt_modified":"2026-04-23T20:35:18.720519+08:00"},{"id":976,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"8eea43550951387ac740b5e3e64c7691","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 94-96","gmt_create":"2026-04-23T20:35:18.72132+08:00","gmt_modified":"2026-04-23T20:35:18.72132+08:00"},{"id":977,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"ed527c7a549ec333c2b30b59614343df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#50-54","gmt_create":"2026-04-23T20:35:18.72244+08:00","gmt_modified":"2026-04-23T20:35:18.72244+08:00"},{"id":978,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"a2adbf02c71e4eb2cf1f120e1a2ff517","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#37-41","gmt_create":"2026-04-23T20:35:18.725156+08:00","gmt_modified":"2026-04-23T20:35:18.725157+08:00"},{"id":979,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"b55cc5936c299f819b57b899858438e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#139-144","gmt_create":"2026-04-23T20:35:18.727146+08:00","gmt_modified":"2026-04-23T20:35:18.727146+08:00"},{"id":980,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"37769b7e6b5588be0065681dedf514ed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/search_engine.py#140-144","gmt_create":"2026-04-23T20:35:18.728033+08:00","gmt_modified":"2026-04-23T20:35:18.728033+08:00"},{"id":981,"source_id":"6a63f048c16c60c5d2d57012c810ee0e","target_id":"37769b7e6b5588be0065681dedf514ed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 140-144","gmt_create":"2026-04-23T20:35:18.728855+08:00","gmt_modified":"2026-04-23T20:35:18.728855+08:00"},{"id":982,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"518d184988b97ebc7ef0c0bf5c10f42c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#24-29","gmt_create":"2026-04-23T20:35:18.72968+08:00","gmt_modified":"2026-04-23T20:35:18.72968+08:00"},{"id":983,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"518d184988b97ebc7ef0c0bf5c10f42c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-29","gmt_create":"2026-04-23T20:35:18.730545+08:00","gmt_modified":"2026-04-23T20:35:18.730546+08:00"},{"id":984,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"818504ee2e17d2f9cc8fe115ca321138","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#34-38","gmt_create":"2026-04-23T20:35:18.73162+08:00","gmt_modified":"2026-04-23T20:35:18.73162+08:00"},{"id":985,"source_id":"6b3d903205941aa9391dd90016e1102c","target_id":"818504ee2e17d2f9cc8fe115ca321138","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-38","gmt_create":"2026-04-23T20:35:18.732614+08:00","gmt_modified":"2026-04-23T20:35:18.732614+08:00"},{"id":986,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#67-71","gmt_create":"2026-04-23T20:35:18.733467+08:00","gmt_modified":"2026-04-23T20:35:18.733467+08:00"},{"id":987,"source_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","target_id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-56","gmt_create":"2026-04-23T20:35:18.735579+08:00","gmt_modified":"2026-04-23T20:35:18.735579+08:00"},{"id":988,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"8a1a0ffd82ac6ff54d3410e4ce59a6b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-56","gmt_create":"2026-04-23T20:35:18.73663+08:00","gmt_modified":"2026-04-23T20:35:18.73663+08:00"},{"id":1012,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"d4f99d3dd9fe489c354edf5fe2f8803d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-44","gmt_create":"2026-04-23T20:35:45.713712+08:00","gmt_modified":"2026-04-23T20:35:45.713713+08:00"},{"id":1015,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"86e37040be1aeb400fab9b529f5404c8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:35:45.722046+08:00","gmt_modified":"2026-04-23T20:35:45.722047+08:00"},{"id":1017,"source_id":"a680d4819f5da57fe9fa0e6bc708f380","target_id":"211463f5b49610f09594c40c0a235943","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-89","gmt_create":"2026-04-23T20:35:45.736063+08:00","gmt_modified":"2026-04-23T20:35:45.736064+08:00"},{"id":1019,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-71","gmt_create":"2026-04-23T20:35:45.743112+08:00","gmt_modified":"2026-04-23T20:35:45.743112+08:00"},{"id":1022,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"98cc82f62b83678f06a33cf9231ecdf8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-128","gmt_create":"2026-04-23T20:35:45.771158+08:00","gmt_modified":"2026-04-23T20:35:45.771158+08:00"},{"id":1024,"source_id":"f6e6948dd0cdd3894bd9928b21feb979","target_id":"e1aabd52989e47806fb997157381e1cf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-37","gmt_create":"2026-04-23T20:35:45.782446+08:00","gmt_modified":"2026-04-23T20:35:45.782446+08:00"},{"id":1028,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"ac77e4875817616194b7b5997d4fb1ae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-94","gmt_create":"2026-04-23T20:35:45.808076+08:00","gmt_modified":"2026-04-23T20:35:45.808076+08:00"},{"id":1030,"source_id":"f6e6948dd0cdd3894bd9928b21feb979","target_id":"0e57efd98dacc85da21f995980371ee4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-37","gmt_create":"2026-04-23T20:35:45.81891+08:00","gmt_modified":"2026-04-23T20:35:45.81891+08:00"},{"id":1033,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"717eb27184726e4f78d694984d29420c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-44","gmt_create":"2026-04-23T20:35:45.831123+08:00","gmt_modified":"2026-04-23T20:35:45.831123+08:00"},{"id":1037,"source_id":"b74caccb06844efcdb14d8324cff65c2","target_id":"bfdf3479f244dc6794628d9df10ab6d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-48","gmt_create":"2026-04-23T20:35:45.842187+08:00","gmt_modified":"2026-04-23T20:35:45.842187+08:00"},{"id":1039,"source_id":"b4a81ef789630d0af6a8d50859d01bf3","target_id":"f5f9f0d96263ae84631c7a8d7e9b3648","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-44","gmt_create":"2026-04-23T20:35:45.84404+08:00","gmt_modified":"2026-04-23T20:35:45.84404+08:00"},{"id":1041,"source_id":"069738f21ac2da7349d22683e8c36929","target_id":"818d1354dc0665798f3d91a2ca5153d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-34","gmt_create":"2026-04-23T20:35:45.845935+08:00","gmt_modified":"2026-04-23T20:35:45.845935+08:00"},{"id":1043,"source_id":"bceca00463fe55d3bcafda728f97f723","target_id":"24aade4c34609a8ab28e4643a3692201","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-36","gmt_create":"2026-04-23T20:35:45.853262+08:00","gmt_modified":"2026-04-23T20:35:45.853263+08:00"},{"id":1045,"source_id":"a680d4819f5da57fe9fa0e6bc708f380","target_id":"d34337b9ff77246979252d2fd8fb8018","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-88","gmt_create":"2026-04-23T20:35:45.866334+08:00","gmt_modified":"2026-04-23T20:35:45.866335+08:00"},{"id":1048,"source_id":"d4f95fcf50683b5bf6167c7d2a6b126d","target_id":"eb63042f04a22f9a67bd498df1684d20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-111","gmt_create":"2026-04-23T20:35:45.883763+08:00","gmt_modified":"2026-04-23T20:35:45.883763+08:00"},{"id":1051,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"c651c7ad6747a92ee96eabb2eb82afdd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-18","gmt_create":"2026-04-23T20:35:45.891674+08:00","gmt_modified":"2026-04-23T20:35:45.891674+08:00"},{"id":1053,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dd01eee487298a28e950f6345196f1d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-79","gmt_create":"2026-04-23T20:35:45.895814+08:00","gmt_modified":"2026-04-23T20:35:45.895814+08:00"},{"id":1055,"source_id":"88d22de3b2a7419868e8ae19130d860c","target_id":"7dae7237f11c5100bf7889c105193cf6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-32","gmt_create":"2026-04-23T20:35:45.901349+08:00","gmt_modified":"2026-04-23T20:35:45.901349+08:00"},{"id":1057,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"cc64cf609f5ff218f618e0664ffa7cc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 298-308","gmt_create":"2026-04-23T20:35:45.904411+08:00","gmt_modified":"2026-04-23T20:35:45.904411+08:00"},{"id":1059,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"ce7e334595a4ce912e0d116314db9a35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 342-429","gmt_create":"2026-04-23T20:35:45.906963+08:00","gmt_modified":"2026-04-23T20:35:45.906964+08:00"},{"id":1061,"source_id":"1a3336b4af8a39a055e912724338580c","target_id":"2f46f212597e3c245b9e5dcc5dbc863d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-18","gmt_create":"2026-04-23T20:35:45.909475+08:00","gmt_modified":"2026-04-23T20:35:45.909476+08:00"},{"id":1063,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"dc40f1dd3e59ee7f046019201068bea1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-22","gmt_create":"2026-04-23T20:35:45.920772+08:00","gmt_modified":"2026-04-23T20:35:45.920772+08:00"},{"id":1069,"source_id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","target_id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: deb919cc-9541-4ed7-a581-ae2876ea67c2 -\u003e a1cc822d-5382-431c-8c49-cf398fb5eb3c","gmt_create":"2026-04-23T20:35:46.950364+08:00","gmt_modified":"2026-04-23T20:35:46.950364+08:00"},{"id":1070,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"37003fc0-1cf5-4264-996b-40807001875f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 37003fc0-1cf5-4264-996b-40807001875f","gmt_create":"2026-04-23T20:35:46.957122+08:00","gmt_modified":"2026-04-23T20:35:46.957122+08:00"},{"id":1071,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2126339b-b0f5-4152-924b-cbe028cd0c39","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 2126339b-b0f5-4152-924b-cbe028cd0c39","gmt_create":"2026-04-23T20:35:46.959782+08:00","gmt_modified":"2026-04-23T20:35:46.959782+08:00"},{"id":1072,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e fab60eaf-9652-4cb5-9f9e-0525caa62d63","gmt_create":"2026-04-23T20:35:46.965729+08:00","gmt_modified":"2026-04-23T20:35:46.965729+08:00"},{"id":1073,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"00359e45-209d-4be3-8795-50dea52bdba1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 00359e45-209d-4be3-8795-50dea52bdba1","gmt_create":"2026-04-23T20:35:46.970985+08:00","gmt_modified":"2026-04-23T20:35:46.970985+08:00"},{"id":1074,"source_id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","target_id":"2632a6f9-774e-4a91-94da-a984bdb20758","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69 -\u003e 2632a6f9-774e-4a91-94da-a984bdb20758","gmt_create":"2026-04-23T20:35:46.974435+08:00","gmt_modified":"2026-04-23T20:35:46.974435+08:00"},{"id":1094,"source_id":"5e414f2ef9b69e55e00ab15f85b9291a","target_id":"01a0c4b40819965823b56e9da858c024","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-15","gmt_create":"2026-04-23T21:00:59.664546+08:00","gmt_modified":"2026-04-23T21:00:59.664546+08:00"},{"id":1101,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"13f6ca76349ef86ae756bb519f122bc5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-150","gmt_create":"2026-04-23T21:00:59.691641+08:00","gmt_modified":"2026-04-23T21:00:59.691641+08:00"},{"id":1103,"source_id":"fb8af100a06778e1fbdac4790a3ed0a9","target_id":"74abd6612105c29b67178fa9dbd04b61","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-27","gmt_create":"2026-04-23T21:00:59.696535+08:00","gmt_modified":"2026-04-23T21:00:59.696535+08:00"},{"id":1105,"source_id":"4d9b59c294a0aac5e300b3de715eb226","target_id":"5bdaabf085a7c3eb6e87c5ad7479e25d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-4","gmt_create":"2026-04-23T21:00:59.697778+08:00","gmt_modified":"2026-04-23T21:00:59.697778+08:00"},{"id":1108,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"9482f4f6279a4f636b77e69b8273b996","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-114","gmt_create":"2026-04-23T21:00:59.700939+08:00","gmt_modified":"2026-04-23T21:00:59.70094+08:00"},{"id":1110,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"397b266f19a1addebdf6c32db71ae77f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-71","gmt_create":"2026-04-23T21:00:59.703412+08:00","gmt_modified":"2026-04-23T21:00:59.703413+08:00"},{"id":1113,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"eb603ec2611957de67af00756f4b1efa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-13","gmt_create":"2026-04-23T21:00:59.713128+08:00","gmt_modified":"2026-04-23T21:00:59.713128+08:00"},{"id":1115,"source_id":"e9b52adbec3c07cf021e488dd3f99ab4","target_id":"c25b39830f3b7734da975acc7f214666","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-33","gmt_create":"2026-04-23T21:00:59.71645+08:00","gmt_modified":"2026-04-23T21:00:59.71645+08:00"},{"id":1117,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"4c9d362ecce8e796e6f14850def049b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-20","gmt_create":"2026-04-23T21:00:59.718148+08:00","gmt_modified":"2026-04-23T21:00:59.718148+08:00"},{"id":1119,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"d5827be2cfbe41c8177660ae877e93a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-34","gmt_create":"2026-04-23T21:00:59.719965+08:00","gmt_modified":"2026-04-23T21:00:59.719965+08:00"},{"id":1121,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"03a65cdcfc173217d12ad8a417f8f033","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-21","gmt_create":"2026-04-23T21:00:59.721352+08:00","gmt_modified":"2026-04-23T21:00:59.721353+08:00"},{"id":1124,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"3365fa8db33d43bab1d0a614e8af3a70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-47","gmt_create":"2026-04-23T21:00:59.724292+08:00","gmt_modified":"2026-04-23T21:00:59.724292+08:00"},{"id":1129,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-34","gmt_create":"2026-04-23T21:00:59.728891+08:00","gmt_modified":"2026-04-23T21:00:59.728891+08:00"},{"id":1132,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"a698e13bfada239280fc9354ff9e2331","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7-8","gmt_create":"2026-04-23T21:00:59.731927+08:00","gmt_modified":"2026-04-23T21:00:59.731927+08:00"},{"id":1134,"source_id":"48a560c49d2b21da327c036ec2934b96","target_id":"37bbab6e4f16db7eac6eee9d05e80e46","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-3","gmt_create":"2026-04-23T21:00:59.737807+08:00","gmt_modified":"2026-04-23T21:00:59.737807+08:00"},{"id":1136,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"63ecbf5e72a0354028b84eb531a58977","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-38","gmt_create":"2026-04-23T21:00:59.738981+08:00","gmt_modified":"2026-04-23T21:00:59.738981+08:00"},{"id":1138,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"bf363deac5ef38c8dc80c73b862e730b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-34","gmt_create":"2026-04-23T21:00:59.740555+08:00","gmt_modified":"2026-04-23T21:00:59.740555+08:00"},{"id":1140,"source_id":"0ef1efea889dba3e1f299626df479571","target_id":"c6e94075e5f689bfa2fe16f8cf965203","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-50","gmt_create":"2026-04-23T21:00:59.742478+08:00","gmt_modified":"2026-04-23T21:00:59.742478+08:00"},{"id":1142,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"1a78f5574add6d07a1d7c947dba3f23d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 115-150","gmt_create":"2026-04-23T21:00:59.743435+08:00","gmt_modified":"2026-04-23T21:00:59.743435+08:00"},{"id":1144,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"f6810849c947471a4b45d7ca01ec8c5f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-9","gmt_create":"2026-04-23T21:00:59.744873+08:00","gmt_modified":"2026-04-23T21:00:59.744873+08:00"},{"id":1146,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"9f6d9941f3b93e29d714bfec7e83434c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-36","gmt_create":"2026-04-23T21:00:59.745747+08:00","gmt_modified":"2026-04-23T21:00:59.745747+08:00"},{"id":1148,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"669d67125dcddb0756f4ff50a43512c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-13","gmt_create":"2026-04-23T21:00:59.746456+08:00","gmt_modified":"2026-04-23T21:00:59.746456+08:00"},{"id":1168,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"85792f0b1e34b5b48b0300aa606ed6e6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-56","gmt_create":"2026-04-23T21:02:44.193893+08:00","gmt_modified":"2026-04-23T21:02:44.193893+08:00"},{"id":1211,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ed630a36e81abafd12787d4095dfe8c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/README.md","gmt_create":"2026-04-24T10:58:35.359267+08:00","gmt_modified":"2026-04-24T10:58:35.359267+08:00"},{"id":1212,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"1cafc02d1d722feb4692dab6ae85c09f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/README.md","gmt_create":"2026-04-24T10:58:35.360113+08:00","gmt_modified":"2026-04-24T10:58:35.360113+08:00"},{"id":1213,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T10:58:35.36047+08:00","gmt_modified":"2026-04-24T10:58:35.36047+08:00"},{"id":1214,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T10:58:35.360788+08:00","gmt_modified":"2026-04-24T10:58:35.360788+08:00"},{"id":1215,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-04-24T10:58:35.361116+08:00","gmt_modified":"2026-04-24T10:58:35.361116+08:00"},{"id":1216,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-04-24T10:58:35.385327+08:00","gmt_modified":"2026-04-24T10:58:35.385328+08:00"},{"id":1217,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-04-24T10:58:35.386483+08:00","gmt_modified":"2026-04-24T10:58:35.386484+08:00"},{"id":1218,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-04-24T10:58:35.386836+08:00","gmt_modified":"2026-04-24T10:58:35.386836+08:00"},{"id":1219,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-04-24T10:58:35.387135+08:00","gmt_modified":"2026-04-24T10:58:35.387135+08:00"},{"id":1220,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-04-24T10:58:35.387467+08:00","gmt_modified":"2026-04-24T10:58:35.387467+08:00"},{"id":1221,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-04-24T10:58:35.38776+08:00","gmt_modified":"2026-04-24T10:58:35.38776+08:00"},{"id":1222,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-04-24T10:58:35.388086+08:00","gmt_modified":"2026-04-24T10:58:35.388086+08:00"},{"id":1223,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"f1a7d61831cc0a45ac6220294f15c21d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-24T10:58:35.388419+08:00","gmt_modified":"2026-04-24T10:58:35.388419+08:00"},{"id":1224,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ef72f0c3cedb9fd9a87352fe493053dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/platforms.ts","gmt_create":"2026-04-24T10:58:35.3887+08:00","gmt_modified":"2026-04-24T10:58:35.3887+08:00"},{"id":1225,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-04-24T10:58:35.388982+08:00","gmt_modified":"2026-04-24T10:58:35.388982+08:00"},{"id":1226,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-04-24T10:58:35.389271+08:00","gmt_modified":"2026-04-24T10:58:35.389271+08:00"},{"id":1227,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-24T10:58:35.389707+08:00","gmt_modified":"2026-04-24T10:58:35.389707+08:00"},{"id":1228,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-04-24T10:58:35.390068+08:00","gmt_modified":"2026-04-24T10:58:35.390068+08:00"},{"id":1229,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-04-24T10:58:35.390413+08:00","gmt_modified":"2026-04-24T10:58:35.390413+08:00"},{"id":1230,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-04-24T10:58:35.390888+08:00","gmt_modified":"2026-04-24T10:58:35.390888+08:00"},{"id":1231,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-84","gmt_create":"2026-04-24T10:58:35.39137+08:00","gmt_modified":"2026-04-24T10:58:35.39137+08:00"},{"id":1232,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-84","gmt_create":"2026-04-24T10:58:35.391735+08:00","gmt_modified":"2026-04-24T10:58:35.391735+08:00"},{"id":1233,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-04-24T10:58:35.393449+08:00","gmt_modified":"2026-04-24T10:58:35.393449+08:00"},{"id":1234,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-04-24T10:58:35.394311+08:00","gmt_modified":"2026-04-24T10:58:35.394312+08:00"},{"id":1235,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-04-24T10:58:35.395171+08:00","gmt_modified":"2026-04-24T10:58:35.395171+08:00"},{"id":1236,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-04-24T10:58:35.397907+08:00","gmt_modified":"2026-04-24T10:58:35.397907+08:00"},{"id":1237,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-04-24T10:58:35.399232+08:00","gmt_modified":"2026-04-24T10:58:35.399232+08:00"},{"id":1238,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-04-24T10:58:35.400157+08:00","gmt_modified":"2026-04-24T10:58:35.400157+08:00"},{"id":1239,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-04-24T10:58:35.400997+08:00","gmt_modified":"2026-04-24T10:58:35.400997+08:00"},{"id":1240,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-04-24T10:58:35.401612+08:00","gmt_modified":"2026-04-24T10:58:35.401612+08:00"},{"id":1241,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"6b9f52af0b6d78c17ff9bbc42d760ea2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/platform-chart.tsx#1-68","gmt_create":"2026-04-24T10:58:35.402427+08:00","gmt_modified":"2026-04-24T10:58:35.402427+08:00"},{"id":1242,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a829403082cc3460c01e0110229c53c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/platforms.ts#1-18","gmt_create":"2026-04-24T10:58:35.409328+08:00","gmt_modified":"2026-04-24T10:58:35.409329+08:00"},{"id":1243,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-154","gmt_create":"2026-04-24T10:58:35.410752+08:00","gmt_modified":"2026-04-24T10:58:35.410752+08:00"},{"id":1244,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-154","gmt_create":"2026-04-24T10:58:35.411143+08:00","gmt_modified":"2026-04-24T10:58:35.411143+08:00"},{"id":1245,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#1-73","gmt_create":"2026-04-24T10:58:35.41196+08:00","gmt_modified":"2026-04-24T10:58:35.41196+08:00"},{"id":1246,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-73","gmt_create":"2026-04-24T10:58:35.412876+08:00","gmt_modified":"2026-04-24T10:58:35.412876+08:00"},{"id":1247,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-04-24T10:58:35.414212+08:00","gmt_modified":"2026-04-24T10:58:35.414212+08:00"},{"id":1248,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"93d8c6a312849c344b6a9713b671840f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-39","gmt_create":"2026-04-24T10:58:35.4148+08:00","gmt_modified":"2026-04-24T10:58:35.4148+08:00"},{"id":1249,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"93d8c6a312849c344b6a9713b671840f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-39","gmt_create":"2026-04-24T10:58:35.415254+08:00","gmt_modified":"2026-04-24T10:58:35.415254+08:00"},{"id":1250,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"71a37a516437e94fd82a87efc70a3f16","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-40","gmt_create":"2026-04-24T10:58:35.416275+08:00","gmt_modified":"2026-04-24T10:58:35.416275+08:00"},{"id":1251,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"844b21a35ae39ead76ff8831eb974e5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#81-84","gmt_create":"2026-04-24T10:58:35.417932+08:00","gmt_modified":"2026-04-24T10:58:35.417932+08:00"},{"id":1252,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"844b21a35ae39ead76ff8831eb974e5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 81-84","gmt_create":"2026-04-24T10:58:35.418732+08:00","gmt_modified":"2026-04-24T10:58:35.418732+08:00"},{"id":1253,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"3af33bd686ce3d418e31843cac66f58b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#12-67","gmt_create":"2026-04-24T10:58:35.422407+08:00","gmt_modified":"2026-04-24T10:58:35.422407+08:00"},{"id":1254,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"3af33bd686ce3d418e31843cac66f58b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-67","gmt_create":"2026-04-24T10:58:35.423436+08:00","gmt_modified":"2026-04-24T10:58:35.423436+08:00"},{"id":1255,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"06c6dfcd66159d42fa9b9eafd1e36a04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/README.md#11-34","gmt_create":"2026-04-24T10:58:35.424232+08:00","gmt_modified":"2026-04-24T10:58:35.424232+08:00"},{"id":1256,"source_id":"1cafc02d1d722feb4692dab6ae85c09f","target_id":"06c6dfcd66159d42fa9b9eafd1e36a04","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-34","gmt_create":"2026-04-24T10:58:35.424616+08:00","gmt_modified":"2026-04-24T10:58:35.424616+08:00"},{"id":1257,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"903da86dc3fb26783f45f247d60e9534","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#69-126","gmt_create":"2026-04-24T10:58:35.426243+08:00","gmt_modified":"2026-04-24T10:58:35.426243+08:00"},{"id":1258,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"903da86dc3fb26783f45f247d60e9534","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-126","gmt_create":"2026-04-24T10:58:35.426634+08:00","gmt_modified":"2026-04-24T10:58:35.426634+08:00"},{"id":1259,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"0ffe337a73c8fb7254f3e48932a8ae7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/README.md#209-234","gmt_create":"2026-04-24T10:58:35.427155+08:00","gmt_modified":"2026-04-24T10:58:35.427155+08:00"},{"id":1260,"source_id":"ed630a36e81abafd12787d4095dfe8c2","target_id":"0ffe337a73c8fb7254f3e48932a8ae7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 209-234","gmt_create":"2026-04-24T10:58:35.427796+08:00","gmt_modified":"2026-04-24T10:58:35.427797+08:00"},{"id":1261,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-123","gmt_create":"2026-04-24T10:58:35.428393+08:00","gmt_modified":"2026-04-24T10:58:35.428393+08:00"},{"id":1262,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#1-104","gmt_create":"2026-04-24T10:58:35.429142+08:00","gmt_modified":"2026-04-24T10:58:35.429142+08:00"},{"id":1263,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"55369db351eb916a3210b22f3d672162","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/README.md#161-170","gmt_create":"2026-04-24T10:58:35.429799+08:00","gmt_modified":"2026-04-24T10:58:35.429799+08:00"},{"id":1264,"source_id":"1cafc02d1d722feb4692dab6ae85c09f","target_id":"55369db351eb916a3210b22f3d672162","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-170","gmt_create":"2026-04-24T10:58:35.430152+08:00","gmt_modified":"2026-04-24T10:58:35.430152+08:00"},{"id":1293,"source_id":"b44632a0f399b2fe2b4daf295a120ec7","target_id":"6c080aba7d0e611bd4e7f268835b630f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-24","gmt_create":"2026-04-24T10:58:51.104849+08:00","gmt_modified":"2026-04-24T10:58:51.104849+08:00"},{"id":1295,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"a7bba55ddc4dd5d215e881e8432d83ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-83","gmt_create":"2026-04-24T10:58:51.105611+08:00","gmt_modified":"2026-04-24T10:58:51.105612+08:00"},{"id":1297,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"7c7425c51cc43b8840cefd9764b47204","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-108","gmt_create":"2026-04-24T10:58:51.106317+08:00","gmt_modified":"2026-04-24T10:58:51.106317+08:00"},{"id":1299,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"6e4a52820e780e4b42651a8214ad4493","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-75","gmt_create":"2026-04-24T10:58:51.10724+08:00","gmt_modified":"2026-04-24T10:58:51.10724+08:00"},{"id":1301,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"4247da3fc00a7e5f8b73775321eccf8e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-77","gmt_create":"2026-04-24T10:58:51.108036+08:00","gmt_modified":"2026-04-24T10:58:51.108036+08:00"},{"id":1303,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-188","gmt_create":"2026-04-24T10:58:51.109999+08:00","gmt_modified":"2026-04-24T10:58:51.109999+08:00"},{"id":1305,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"557281ca025f76d0dc2db67e56b44053","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-155","gmt_create":"2026-04-24T10:58:51.111471+08:00","gmt_modified":"2026-04-24T10:58:51.111472+08:00"},{"id":1307,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"e2d4838e58acc0eee236ef586abab64e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-48","gmt_create":"2026-04-24T10:58:51.113574+08:00","gmt_modified":"2026-04-24T10:58:51.113574+08:00"},{"id":1309,"source_id":"b0c428683c8a3e6922d90ca0d8c2736d","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-29","gmt_create":"2026-04-24T10:58:51.114869+08:00","gmt_modified":"2026-04-24T10:58:51.114869+08:00"},{"id":1311,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"acd9e6c32084e589d5aeb1665d918dfd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-43","gmt_create":"2026-04-24T10:58:51.115783+08:00","gmt_modified":"2026-04-24T10:58:51.115783+08:00"},{"id":1313,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-48","gmt_create":"2026-04-24T10:58:51.116484+08:00","gmt_modified":"2026-04-24T10:58:51.116484+08:00"},{"id":1315,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-83","gmt_create":"2026-04-24T10:58:51.117511+08:00","gmt_modified":"2026-04-24T10:58:51.117511+08:00"},{"id":1317,"source_id":"b44632a0f399b2fe2b4daf295a120ec7","target_id":"9357a0fcca02068d428f4a191d08fdcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-24","gmt_create":"2026-04-24T10:58:51.118728+08:00","gmt_modified":"2026-04-24T10:58:51.118728+08:00"},{"id":1320,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"8efcce12915471fe5b88fe058bcf238e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-69","gmt_create":"2026-04-24T10:58:51.120028+08:00","gmt_modified":"2026-04-24T10:58:51.120028+08:00"},{"id":1322,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-188","gmt_create":"2026-04-24T10:58:51.124562+08:00","gmt_modified":"2026-04-24T10:58:51.124562+08:00"},{"id":1324,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"f4d57f9a78585969a006b7451ea8ce84","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-155","gmt_create":"2026-04-24T10:58:51.125712+08:00","gmt_modified":"2026-04-24T10:58:51.125712+08:00"},{"id":1330,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"608c00e1835ad72363ef08796961faca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-17","gmt_create":"2026-04-24T10:58:51.129154+08:00","gmt_modified":"2026-04-24T10:58:51.129154+08:00"},{"id":1342,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"ec4bf600a513dc2b014c85e141d7582d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-85","gmt_create":"2026-04-24T10:58:51.139025+08:00","gmt_modified":"2026-04-24T10:58:51.139026+08:00"},{"id":1356,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"9606b8243736b4a6f5ecfe152b2ab6dd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-83","gmt_create":"2026-04-24T10:58:51.158662+08:00","gmt_modified":"2026-04-24T10:58:51.158662+08:00"},{"id":1358,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-108","gmt_create":"2026-04-24T10:58:51.160297+08:00","gmt_modified":"2026-04-24T10:58:51.160297+08:00"},{"id":1360,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"3d85cad939ce858f9c6d153d425c19fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-155","gmt_create":"2026-04-24T10:58:51.163075+08:00","gmt_modified":"2026-04-24T10:58:51.163075+08:00"},{"id":1362,"source_id":"5013cbe89f1c6f03533eb218400cedb0","target_id":"36769bd305cd5f664fa6e28f82e4b3e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-24T10:58:51.164477+08:00","gmt_modified":"2026-04-24T10:58:51.164477+08:00"},{"id":1364,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-75","gmt_create":"2026-04-24T10:58:51.166362+08:00","gmt_modified":"2026-04-24T10:58:51.166363+08:00"},{"id":1392,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"1f8d26b6a5da49d89d95bb13c7ace2c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-48","gmt_create":"2026-04-24T10:59:38.934235+08:00","gmt_modified":"2026-04-24T10:59:38.934235+08:00"},{"id":1403,"source_id":"b0cb6810919f64006be7aa66b2b76a61","target_id":"c8f2dbcb7475bd189a34c7061ea46c6d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-41","gmt_create":"2026-04-24T10:59:38.943933+08:00","gmt_modified":"2026-04-24T10:59:38.943933+08:00"},{"id":1407,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-175","gmt_create":"2026-04-24T10:59:38.9463+08:00","gmt_modified":"2026-04-24T10:59:38.9463+08:00"},{"id":1409,"source_id":"c59f8c276697a070dffc581fe94d809c","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-48","gmt_create":"2026-04-24T10:59:38.947981+08:00","gmt_modified":"2026-04-24T10:59:38.947981+08:00"},{"id":1417,"source_id":"b0cb6810919f64006be7aa66b2b76a61","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-41","gmt_create":"2026-04-24T10:59:38.954222+08:00","gmt_modified":"2026-04-24T10:59:38.954223+08:00"},{"id":1427,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"fe351bf59a46bec7f77ffe40a68a5993","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-56","gmt_create":"2026-04-24T10:59:38.965521+08:00","gmt_modified":"2026-04-24T10:59:38.965521+08:00"},{"id":1435,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-107","gmt_create":"2026-04-24T10:59:38.971032+08:00","gmt_modified":"2026-04-24T10:59:38.971032+08:00"},{"id":1437,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 110-140","gmt_create":"2026-04-24T10:59:38.97203+08:00","gmt_modified":"2026-04-24T10:59:38.97203+08:00"},{"id":1439,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"1153d8a149a70bc79ca59a9dcba5945c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-55","gmt_create":"2026-04-24T10:59:38.972843+08:00","gmt_modified":"2026-04-24T10:59:38.972843+08:00"},{"id":1441,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-115","gmt_create":"2026-04-24T10:59:38.973675+08:00","gmt_modified":"2026-04-24T10:59:38.973675+08:00"},{"id":1461,"source_id":"18a0651d895fba9bb4e0c0229459efdc","target_id":"dc735ee4a0f12140bcee122a67f4a13b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-63","gmt_create":"2026-04-24T11:01:58.090246+08:00","gmt_modified":"2026-04-24T11:01:58.090246+08:00"},{"id":1465,"source_id":"955e1dfe57f0a9a8e900383eb7641ba1","target_id":"f990ecd63842b3ab82f5b8c8dcde2a6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-5","gmt_create":"2026-04-24T11:01:58.092029+08:00","gmt_modified":"2026-04-24T11:01:58.092029+08:00"},{"id":1468,"source_id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","target_id":"d5efa0fbc545b778dd913854d860c502","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-04-24T11:01:58.095303+08:00","gmt_modified":"2026-04-24T11:01:58.095304+08:00"},{"id":1473,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-04-24T11:02:17.577219+08:00","gmt_modified":"2026-04-24T11:02:17.577219+08:00"},{"id":1474,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-04-24T11:02:17.578316+08:00","gmt_modified":"2026-04-24T11:02:17.578316+08:00"},{"id":1475,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-04-24T11:02:17.579016+08:00","gmt_modified":"2026-04-24T11:02:17.579016+08:00"},{"id":1476,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-04-24T11:02:17.579604+08:00","gmt_modified":"2026-04-24T11:02:17.579604+08:00"},{"id":1477,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-04-24T11:02:17.580669+08:00","gmt_modified":"2026-04-24T11:02:17.580669+08:00"},{"id":1478,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-04-24T11:02:17.581765+08:00","gmt_modified":"2026-04-24T11:02:17.581765+08:00"},{"id":1479,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-04-24T11:02:17.582245+08:00","gmt_modified":"2026-04-24T11:02:17.582245+08:00"},{"id":1480,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-04-24T11:02:17.582573+08:00","gmt_modified":"2026-04-24T11:02:17.582573+08:00"},{"id":1481,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-24T11:02:17.582943+08:00","gmt_modified":"2026-04-24T11:02:17.582943+08:00"},{"id":1482,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b0cb6810919f64006be7aa66b2b76a61","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-04-24T11:02:17.58335+08:00","gmt_modified":"2026-04-24T11:02:17.58335+08:00"},{"id":1483,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-04-24T11:02:17.583672+08:00","gmt_modified":"2026-04-24T11:02:17.583673+08:00"},{"id":1484,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-04-24T11:02:17.583973+08:00","gmt_modified":"2026-04-24T11:02:17.583973+08:00"},{"id":1485,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5800a08224424ebced854d06365f6d44","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(auth","gmt_create":"2026-04-24T11:02:17.584307+08:00","gmt_modified":"2026-04-24T11:02:17.584307+08:00"},{"id":1486,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"37d7291b1373216dcf08f081a94ab1c8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: /Users/Chiguyong/Code/GEO#wiki#main#wiki#zh/[frontend/app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","gmt_create":"2026-04-24T11:02:17.585037+08:00","gmt_modified":"2026-04-24T11:02:17.585037+08:00"},{"id":1487,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-04-24T11:02:17.585369+08:00","gmt_modified":"2026-04-24T11:02:17.585369+08:00"},{"id":1488,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-04-24T11:02:17.585874+08:00","gmt_modified":"2026-04-24T11:02:17.585874+08:00"},{"id":1489,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46434c04e402674d97a6e2017a3a13c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-62","gmt_create":"2026-04-24T11:02:17.58637+08:00","gmt_modified":"2026-04-24T11:02:17.58637+08:00"},{"id":1490,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"46434c04e402674d97a6e2017a3a13c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-62","gmt_create":"2026-04-24T11:02:17.586722+08:00","gmt_modified":"2026-04-24T11:02:17.586723+08:00"},{"id":1491,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"3a0fd619768c80d413f8b02b3daec229","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-175","gmt_create":"2026-04-24T11:02:17.587241+08:00","gmt_modified":"2026-04-24T11:02:17.587241+08:00"},{"id":1492,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"3a0fd619768c80d413f8b02b3daec229","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-175","gmt_create":"2026-04-24T11:02:17.587532+08:00","gmt_modified":"2026-04-24T11:02:17.587532+08:00"},{"id":1493,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"86af0295eebcd62f33207e158db86c81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-115","gmt_create":"2026-04-24T11:02:17.58823+08:00","gmt_modified":"2026-04-24T11:02:17.58823+08:00"},{"id":1494,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"86af0295eebcd62f33207e158db86c81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-115","gmt_create":"2026-04-24T11:02:17.588592+08:00","gmt_modified":"2026-04-24T11:02:17.588592+08:00"},{"id":1495,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#21-41","gmt_create":"2026-04-24T11:02:17.589011+08:00","gmt_modified":"2026-04-24T11:02:17.589011+08:00"},{"id":1496,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"809fc86e3ce390a1af1db1e0cd5ad787","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#55-84","gmt_create":"2026-04-24T11:02:17.589558+08:00","gmt_modified":"2026-04-24T11:02:17.589558+08:00"},{"id":1497,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"809fc86e3ce390a1af1db1e0cd5ad787","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 55-84","gmt_create":"2026-04-24T11:02:17.589968+08:00","gmt_modified":"2026-04-24T11:02:17.589968+08:00"},{"id":1498,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-48","gmt_create":"2026-04-24T11:02:17.590369+08:00","gmt_modified":"2026-04-24T11:02:17.590369+08:00"},{"id":1499,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-04-24T11:02:17.591152+08:00","gmt_modified":"2026-04-24T11:02:17.591152+08:00"},{"id":1500,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"608c00e1835ad72363ef08796961faca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-17","gmt_create":"2026-04-24T11:02:17.59504+08:00","gmt_modified":"2026-04-24T11:02:17.59504+08:00"},{"id":1501,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-29","gmt_create":"2026-04-24T11:02:17.595846+08:00","gmt_modified":"2026-04-24T11:02:17.595846+08:00"},{"id":1502,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"29ee02d164db08d7b9bd4591195e191b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#5-56","gmt_create":"2026-04-24T11:02:17.596584+08:00","gmt_modified":"2026-04-24T11:02:17.596584+08:00"},{"id":1503,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"29ee02d164db08d7b9bd4591195e191b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-56","gmt_create":"2026-04-24T11:02:17.596923+08:00","gmt_modified":"2026-04-24T11:02:17.596923+08:00"},{"id":1504,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"73c4889fcacaea737921a568bf20383d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#13-32","gmt_create":"2026-04-24T11:02:17.598958+08:00","gmt_modified":"2026-04-24T11:02:17.598958+08:00"},{"id":1505,"source_id":"d2c1984414de6856ed5b3873c661b712","target_id":"73c4889fcacaea737921a568bf20383d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-32","gmt_create":"2026-04-24T11:02:17.599388+08:00","gmt_modified":"2026-04-24T11:02:17.599389+08:00"},{"id":1506,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"11c2505e56ba9a48c50be4c915f22c9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#27-37","gmt_create":"2026-04-24T11:02:17.601161+08:00","gmt_modified":"2026-04-24T11:02:17.601161+08:00"},{"id":1507,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"11c2505e56ba9a48c50be4c915f22c9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-37","gmt_create":"2026-04-24T11:02:17.601545+08:00","gmt_modified":"2026-04-24T11:02:17.601545+08:00"},{"id":1508,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5f32b18b18cea3b2bdc9150366c24e5e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#26-37","gmt_create":"2026-04-24T11:02:17.601968+08:00","gmt_modified":"2026-04-24T11:02:17.601968+08:00"},{"id":1509,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"5f32b18b18cea3b2bdc9150366c24e5e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-37","gmt_create":"2026-04-24T11:02:17.602636+08:00","gmt_modified":"2026-04-24T11:02:17.602636+08:00"},{"id":1510,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c4abaa8a82ad75d09ee66f97fbad4b96","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-10","gmt_create":"2026-04-24T11:02:17.603102+08:00","gmt_modified":"2026-04-24T11:02:17.603102+08:00"},{"id":1511,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"c4abaa8a82ad75d09ee66f97fbad4b96","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-10","gmt_create":"2026-04-24T11:02:17.603401+08:00","gmt_modified":"2026-04-24T11:02:17.603402+08:00"},{"id":1512,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"08ac91fb508b386f0e6c66e53b03a471","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-11","gmt_create":"2026-04-24T11:02:17.604811+08:00","gmt_modified":"2026-04-24T11:02:17.604811+08:00"},{"id":1513,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"08ac91fb508b386f0e6c66e53b03a471","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-11","gmt_create":"2026-04-24T11:02:17.60518+08:00","gmt_modified":"2026-04-24T11:02:17.60518+08:00"},{"id":1514,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"d4ea500c0acb4ebf267a44908e23f787","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#40-55","gmt_create":"2026-04-24T11:02:17.605584+08:00","gmt_modified":"2026-04-24T11:02:17.605584+08:00"},{"id":1515,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"d4ea500c0acb4ebf267a44908e23f787","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-55","gmt_create":"2026-04-24T11:02:17.605874+08:00","gmt_modified":"2026-04-24T11:02:17.605874+08:00"},{"id":1516,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"b4f0bea37f71296167571d8831ebe6d5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-58","gmt_create":"2026-04-24T11:02:17.60772+08:00","gmt_modified":"2026-04-24T11:02:17.607721+08:00"},{"id":1517,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"b4f0bea37f71296167571d8831ebe6d5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-58","gmt_create":"2026-04-24T11:02:17.608058+08:00","gmt_modified":"2026-04-24T11:02:17.608058+08:00"},{"id":1518,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46f7431da5eb82bbd7686a71abaddf78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#42-57","gmt_create":"2026-04-24T11:02:17.608532+08:00","gmt_modified":"2026-04-24T11:02:17.608532+08:00"},{"id":1519,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"46f7431da5eb82bbd7686a71abaddf78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-57","gmt_create":"2026-04-24T11:02:17.608872+08:00","gmt_modified":"2026-04-24T11:02:17.608872+08:00"},{"id":1520,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"0ba2ea54873608360c48c8b5aaeea20f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#58-71","gmt_create":"2026-04-24T11:02:17.609376+08:00","gmt_modified":"2026-04-24T11:02:17.609376+08:00"},{"id":1521,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"0ba2ea54873608360c48c8b5aaeea20f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 58-71","gmt_create":"2026-04-24T11:02:17.609794+08:00","gmt_modified":"2026-04-24T11:02:17.609794+08:00"},{"id":1522,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"2d170933ae8c838199f6d68a2b9165c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#61-84","gmt_create":"2026-04-24T11:02:17.610895+08:00","gmt_modified":"2026-04-24T11:02:17.610895+08:00"},{"id":1523,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"2d170933ae8c838199f6d68a2b9165c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-84","gmt_create":"2026-04-24T11:02:17.6112+08:00","gmt_modified":"2026-04-24T11:02:17.6112+08:00"},{"id":1524,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"0ea85b56099b9087bd22eec96b7bb752","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-140","gmt_create":"2026-04-24T11:02:17.611696+08:00","gmt_modified":"2026-04-24T11:02:17.611696+08:00"},{"id":1525,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"0ea85b56099b9087bd22eec96b7bb752","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-140","gmt_create":"2026-04-24T11:02:17.612307+08:00","gmt_modified":"2026-04-24T11:02:17.612307+08:00"},{"id":1526,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"2a4087b6941ca17dd651147f2f23451c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-90","gmt_create":"2026-04-24T11:02:17.613704+08:00","gmt_modified":"2026-04-24T11:02:17.613704+08:00"},{"id":1527,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"2a4087b6941ca17dd651147f2f23451c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-90","gmt_create":"2026-04-24T11:02:17.614071+08:00","gmt_modified":"2026-04-24T11:02:17.614071+08:00"},{"id":1528,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"88c12e200d5c3ea53c695aa4209cecd9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#65-76","gmt_create":"2026-04-24T11:02:17.614574+08:00","gmt_modified":"2026-04-24T11:02:17.614574+08:00"},{"id":1529,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"88c12e200d5c3ea53c695aa4209cecd9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 65-76","gmt_create":"2026-04-24T11:02:17.615017+08:00","gmt_modified":"2026-04-24T11:02:17.615017+08:00"},{"id":1530,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#110-140","gmt_create":"2026-04-24T11:02:17.615713+08:00","gmt_modified":"2026-04-24T11:02:17.615713+08:00"},{"id":1531,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"42b92d878423a23067e9a6da104e3a5e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#79-90","gmt_create":"2026-04-24T11:02:17.616887+08:00","gmt_modified":"2026-04-24T11:02:17.616888+08:00"},{"id":1532,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"42b92d878423a23067e9a6da104e3a5e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-90","gmt_create":"2026-04-24T11:02:17.617309+08:00","gmt_modified":"2026-04-24T11:02:17.617309+08:00"},{"id":1533,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-107","gmt_create":"2026-04-24T11:02:17.617785+08:00","gmt_modified":"2026-04-24T11:02:17.617785+08:00"},{"id":1534,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"abadc99952ad6e00ab4bfb66b84732bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#33-41","gmt_create":"2026-04-24T11:02:17.618924+08:00","gmt_modified":"2026-04-24T11:02:17.618925+08:00"},{"id":1535,"source_id":"e0c0ca66b8b81cf66e078a7ab162c07f","target_id":"abadc99952ad6e00ab4bfb66b84732bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-41","gmt_create":"2026-04-24T11:02:17.619333+08:00","gmt_modified":"2026-04-24T11:02:17.619333+08:00"},{"id":1536,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f784a33e47128515d518555d99103f62","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#143-175","gmt_create":"2026-04-24T11:02:17.619742+08:00","gmt_modified":"2026-04-24T11:02:17.619742+08:00"},{"id":1537,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"f784a33e47128515d518555d99103f62","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 143-175","gmt_create":"2026-04-24T11:02:17.620025+08:00","gmt_modified":"2026-04-24T11:02:17.620025+08:00"},{"id":1538,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"173f8de5896e18fc81cdd5d72e2a8c07","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#93-115","gmt_create":"2026-04-24T11:02:17.621068+08:00","gmt_modified":"2026-04-24T11:02:17.621068+08:00"},{"id":1539,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"173f8de5896e18fc81cdd5d72e2a8c07","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 93-115","gmt_create":"2026-04-24T11:02:17.62207+08:00","gmt_modified":"2026-04-24T11:02:17.62207+08:00"},{"id":1540,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"3ab144009e705151f69698d2d8a81cea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#35-37","gmt_create":"2026-04-24T11:02:17.622971+08:00","gmt_modified":"2026-04-24T11:02:17.622972+08:00"},{"id":1541,"source_id":"4d2f3847b7c10634733118b70a1aea0b","target_id":"3ab144009e705151f69698d2d8a81cea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-37","gmt_create":"2026-04-24T11:02:17.623434+08:00","gmt_modified":"2026-04-24T11:02:17.623434+08:00"},{"id":1542,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"570a917d85850ab1208fce5823b110a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#60-62","gmt_create":"2026-04-24T11:02:17.62436+08:00","gmt_modified":"2026-04-24T11:02:17.62436+08:00"},{"id":1543,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"570a917d85850ab1208fce5823b110a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 60-62","gmt_create":"2026-04-24T11:02:17.624694+08:00","gmt_modified":"2026-04-24T11:02:17.624694+08:00"},{"id":1544,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"f92c0c41197c488f04f994bf0f7ea465","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#87-104","gmt_create":"2026-04-24T11:02:17.625099+08:00","gmt_modified":"2026-04-24T11:02:17.625099+08:00"},{"id":1545,"source_id":"389d631bc6c7111ba411b0b79fca455e","target_id":"f92c0c41197c488f04f994bf0f7ea465","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 87-104","gmt_create":"2026-04-24T11:02:17.625385+08:00","gmt_modified":"2026-04-24T11:02:17.625385+08:00"},{"id":1546,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"5688471e2418628ac2a6409451708d06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-115","gmt_create":"2026-04-24T11:02:17.626962+08:00","gmt_modified":"2026-04-24T11:02:17.626962+08:00"},{"id":1547,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"5688471e2418628ac2a6409451708d06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-115","gmt_create":"2026-04-24T11:02:17.627296+08:00","gmt_modified":"2026-04-24T11:02:17.627296+08:00"},{"id":1548,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-04-24T11:02:17.62778+08:00","gmt_modified":"2026-04-24T11:02:17.62778+08:00"},{"id":1549,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-175","gmt_create":"2026-04-24T11:02:17.628417+08:00","gmt_modified":"2026-04-24T11:02:17.628417+08:00"},{"id":1550,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-04-24T11:02:17.629023+08:00","gmt_modified":"2026-04-24T11:02:17.629023+08:00"},{"id":1551,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-04-24T11:02:17.629535+08:00","gmt_modified":"2026-04-24T11:02:17.629535+08:00"},{"id":1552,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-04-24T11:02:17.630073+08:00","gmt_modified":"2026-04-24T11:02:17.630073+08:00"},{"id":1553,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-104","gmt_create":"2026-04-24T11:02:17.632419+08:00","gmt_modified":"2026-04-24T11:02:17.632419+08:00"},{"id":1554,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"7075cde1c771c46dbbd37b3c09dac53d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#20-41","gmt_create":"2026-04-24T11:02:17.633252+08:00","gmt_modified":"2026-04-24T11:02:17.633252+08:00"},{"id":1555,"source_id":"9d08667997a868fc07c9b4e328e44224","target_id":"7075cde1c771c46dbbd37b3c09dac53d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-41","gmt_create":"2026-04-24T11:02:17.636427+08:00","gmt_modified":"2026-04-24T11:02:17.636427+08:00"},{"id":1556,"source_id":"df661133-efbf-43fe-97c3-f581c81f47a7","target_id":"607e99e751640281d26516c772548b93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#17-39","gmt_create":"2026-04-24T11:02:17.637267+08:00","gmt_modified":"2026-04-24T11:02:17.637267+08:00"},{"id":1557,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"607e99e751640281d26516c772548b93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17-39","gmt_create":"2026-04-24T11:02:17.637632+08:00","gmt_modified":"2026-04-24T11:02:17.637632+08:00"},{"id":1583,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-78","gmt_create":"2026-04-24T11:02:30.048441+08:00","gmt_modified":"2026-04-24T11:02:30.048441+08:00"},{"id":1585,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"10d3948b1394ffa0110796edfa0bfc25","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30","gmt_create":"2026-04-24T11:02:30.050019+08:00","gmt_modified":"2026-04-24T11:02:30.050019+08:00"},{"id":1589,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"3c41910bad9855635d1362efc314463a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 15","gmt_create":"2026-04-24T11:02:30.051832+08:00","gmt_modified":"2026-04-24T11:02:30.051832+08:00"},{"id":1591,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"f32e078c985967af30d2c526290d9acb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23","gmt_create":"2026-04-24T11:02:30.052506+08:00","gmt_modified":"2026-04-24T11:02:30.052506+08:00"},{"id":1593,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"c10a89cdd47474f51664a239b82cc2e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 17","gmt_create":"2026-04-24T11:02:30.05328+08:00","gmt_modified":"2026-04-24T11:02:30.05328+08:00"},{"id":1596,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"d6ebce8c7d9e9de127486400670ebed0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-84","gmt_create":"2026-04-24T11:02:30.054595+08:00","gmt_modified":"2026-04-24T11:02:30.054595+08:00"},{"id":1599,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"ec3ed02cad3cd8af4bacb5c978273092","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-77","gmt_create":"2026-04-24T11:02:30.056273+08:00","gmt_modified":"2026-04-24T11:02:30.056273+08:00"},{"id":1603,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"2db9940a42c91fc92f23595491ea93d1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 67-78","gmt_create":"2026-04-24T11:02:30.058168+08:00","gmt_modified":"2026-04-24T11:02:30.058168+08:00"},{"id":1609,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"68fbb2bd365f96a98ea187a9738c4460","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-57","gmt_create":"2026-04-24T11:02:30.061204+08:00","gmt_modified":"2026-04-24T11:02:30.061204+08:00"},{"id":1619,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"44f9c9f195e096efbd6c6a6f97880944","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-75","gmt_create":"2026-04-24T11:02:30.069323+08:00","gmt_modified":"2026-04-24T11:02:30.069323+08:00"},{"id":1621,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"cbe8ffc1cfb98ac79c7659e968191837","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 343-466","gmt_create":"2026-04-24T11:02:30.070073+08:00","gmt_modified":"2026-04-24T11:02:30.070073+08:00"},{"id":1624,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"97f9b6149bd43feb0f69cf2582ab6305","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 85-117","gmt_create":"2026-04-24T11:02:30.071724+08:00","gmt_modified":"2026-04-24T11:02:30.071724+08:00"},{"id":1626,"source_id":"5013cbe89f1c6f03533eb218400cedb0","target_id":"ce4de96353f8f81ca825173ddbec1150","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-41","gmt_create":"2026-04-24T11:02:30.072769+08:00","gmt_modified":"2026-04-24T11:02:30.072769+08:00"},{"id":1628,"source_id":"b250fc6c32106a7f3e0c3ad152dfc097","target_id":"a87a1a7c1723518159d5818c197996cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-155","gmt_create":"2026-04-24T11:02:30.073474+08:00","gmt_modified":"2026-04-24T11:02:30.073474+08:00"},{"id":1630,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-45","gmt_create":"2026-04-24T11:02:30.074211+08:00","gmt_modified":"2026-04-24T11:02:30.074211+08:00"},{"id":1632,"source_id":"3809c5ab912511e0e093ba02a4fc918f","target_id":"f7314a4515e822cba6f37d7a8f1970f3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-46","gmt_create":"2026-04-24T11:02:30.074964+08:00","gmt_modified":"2026-04-24T11:02:30.074964+08:00"},{"id":1635,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"ef31f4aa4fbd1b6ff76eba467b757a04","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-69","gmt_create":"2026-04-24T11:02:30.076612+08:00","gmt_modified":"2026-04-24T11:02:30.076612+08:00"},{"id":1646,"source_id":"93022c8938ce318f167277cfa65c29a7","target_id":"3a7201f4564dbcf35c5771f1b5d58cb6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 46-50","gmt_create":"2026-04-24T11:02:30.084522+08:00","gmt_modified":"2026-04-24T11:02:30.084522+08:00"},{"id":1650,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"39c3dbe67ab2ae74446fe6a118bd8738","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-29","gmt_create":"2026-04-24T11:02:30.086409+08:00","gmt_modified":"2026-04-24T11:02:30.08641+08:00"},{"id":1652,"source_id":"5386144bf3c668c6fa14481c0d85a214","target_id":"68d937267aab2509edc0c7b67e1b5ef6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-57","gmt_create":"2026-04-24T11:02:30.087245+08:00","gmt_modified":"2026-04-24T11:02:30.087245+08:00"},{"id":1654,"source_id":"f26740f2a1532b38c816663a4f665dbf","target_id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-25","gmt_create":"2026-04-24T11:02:30.08803+08:00","gmt_modified":"2026-04-24T11:02:30.08803+08:00"},{"id":1656,"source_id":"5883a8ef4fc156d76b71ffdb5ecdf232","target_id":"a9c1b0716ae36af22fce6148c2e40ce5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-49","gmt_create":"2026-04-24T11:02:30.088761+08:00","gmt_modified":"2026-04-24T11:02:30.088762+08:00"},{"id":1657,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"2793782c-91c8-4052-b9db-39513426c736","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 2793782c-91c8-4052-b9db-39513426c736","gmt_create":"2026-04-24T11:08:43.063241+08:00","gmt_modified":"2026-04-24T11:08:43.063241+08:00"},{"id":1658,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"e23bd86e-b4ac-40eb-b1c1-38d929fd5419","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e e23bd86e-b4ac-40eb-b1c1-38d929fd5419","gmt_create":"2026-04-24T11:08:43.063978+08:00","gmt_modified":"2026-04-24T11:08:43.063978+08:00"},{"id":1659,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"70b3948e-f456-42d2-b7ad-a0097ad5ee5f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 70b3948e-f456-42d2-b7ad-a0097ad5ee5f","gmt_create":"2026-04-24T11:08:43.064613+08:00","gmt_modified":"2026-04-24T11:08:43.064613+08:00"},{"id":1661,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"7e679d62-c415-4d6a-a7e5-d41d00e0ed69","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 7e679d62-c415-4d6a-a7e5-d41d00e0ed69","gmt_create":"2026-04-24T11:08:43.065797+08:00","gmt_modified":"2026-04-24T11:08:43.065797+08:00"},{"id":1686,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-05-23T15:16:36.206816+08:00","gmt_modified":"2026-05-23T15:16:36.206817+08:00"},{"id":1687,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-05-23T15:16:36.207764+08:00","gmt_modified":"2026-05-23T15:16:36.207764+08:00"},{"id":1688,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"80a0429cc47931de27ddb17a62b8dd9c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_business_flow.py","gmt_create":"2026-05-23T15:16:36.210436+08:00","gmt_modified":"2026-05-23T15:16:36.210436+08:00"},{"id":1689,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b07a4fb9cecbbd66a6910ccbc7651f19","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citation_engine.py","gmt_create":"2026-05-23T15:16:36.211921+08:00","gmt_modified":"2026-05-23T15:16:36.211921+08:00"},{"id":1690,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"42ff5383133d176cec9eb88682483be3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_citations.py","gmt_create":"2026-05-23T15:16:36.213087+08:00","gmt_modified":"2026-05-23T15:16:36.213087+08:00"},{"id":1691,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1eb698126da2b6c95924e3ca32115e3a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_content_agents.py","gmt_create":"2026-05-23T15:16:36.213756+08:00","gmt_modified":"2026-05-23T15:16:36.213756+08:00"},{"id":1692,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"ff5699698ead454bb1137030cf21c533","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_llm_provider.py","gmt_create":"2026-05-23T15:16:36.214345+08:00","gmt_modified":"2026-05-23T15:16:36.214345+08:00"},{"id":1693,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"a8bfbe8f5db65abf625c19edc3999a97","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_pipeline_engine.py","gmt_create":"2026-05-23T15:16:36.21477+08:00","gmt_modified":"2026-05-23T15:16:36.21477+08:00"},{"id":1694,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"0bfe423695374ece56313bb55e9d3e86","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_platform_rules.py","gmt_create":"2026-05-23T15:16:36.215178+08:00","gmt_modified":"2026-05-23T15:16:36.215178+08:00"},{"id":1695,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"bbcb3a67f564dd7c05d3f8684c9bf8c6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_prompt_template.py","gmt_create":"2026-05-23T15:16:36.215561+08:00","gmt_modified":"2026-05-23T15:16:36.215561+08:00"},{"id":1696,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"0613e76b9679be7f998fb8fd8056e686","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_queries.py","gmt_create":"2026-05-23T15:16:36.215949+08:00","gmt_modified":"2026-05-23T15:16:36.215949+08:00"},{"id":1697,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"2aab65d07faab01583455277d363742f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_rag_service.py","gmt_create":"2026-05-23T15:16:36.216332+08:00","gmt_modified":"2026-05-23T15:16:36.216332+08:00"},{"id":1698,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b2f0d46a31a5441594f2e777365fc156","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_scheduler.py","gmt_create":"2026-05-23T15:16:36.216833+08:00","gmt_modified":"2026-05-23T15:16:36.216833+08:00"},{"id":1699,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"af7c8d3b4ba659f1bd8c4989b5ed7a62","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/tests/test_integration/test_full_flow.py","gmt_create":"2026-05-23T15:16:36.217275+08:00","gmt_modified":"2026-05-23T15:16:36.217275+08:00"},{"id":1700,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:16:36.217851+08:00","gmt_modified":"2026-05-23T15:16:36.217851+08:00"},{"id":1701,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-05-23T15:16:36.218458+08:00","gmt_modified":"2026-05-23T15:16:36.218458+08:00"},{"id":1702,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:16:36.218906+08:00","gmt_modified":"2026-05-23T15:16:36.218906+08:00"},{"id":1703,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-05-23T15:16:36.2202+08:00","gmt_modified":"2026-05-23T15:16:36.2202+08:00"},{"id":1704,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-05-23T15:16:36.220695+08:00","gmt_modified":"2026-05-23T15:16:36.220695+08:00"},{"id":1705,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:16:36.221198+08:00","gmt_modified":"2026-05-23T15:16:36.221198+08:00"},{"id":1706,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:16:36.221874+08:00","gmt_modified":"2026-05-23T15:16:36.221874+08:00"},{"id":1707,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-05-23T15:16:36.222439+08:00","gmt_modified":"2026-05-23T15:16:36.222439+08:00"},{"id":1708,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-05-23T15:16:36.222865+08:00","gmt_modified":"2026-05-23T15:16:36.222866+08:00"},{"id":1709,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:16:36.223258+08:00","gmt_modified":"2026-05-23T15:16:36.223258+08:00"},{"id":1710,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"13b8f594e7cace5c8a9255dc801dcad8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/content_generator_agent.py","gmt_create":"2026-05-23T15:16:36.223801+08:00","gmt_modified":"2026-05-23T15:16:36.223801+08:00"},{"id":1711,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"750f8d79d83ee910e9d18e8a4fe37e22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/deai_agent.py","gmt_create":"2026-05-23T15:16:36.224278+08:00","gmt_modified":"2026-05-23T15:16:36.224278+08:00"},{"id":1712,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7f8c6e94ead45ad9bab8cea9a7be2123","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/geo_optimizer_agent.py","gmt_create":"2026-05-23T15:16:36.224716+08:00","gmt_modified":"2026-05-23T15:16:36.224716+08:00"},{"id":1713,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"609a02c9e1ccc0311885a70578b86386","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/engine.py","gmt_create":"2026-05-23T15:16:36.227597+08:00","gmt_modified":"2026-05-23T15:16:36.227597+08:00"},{"id":1714,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"43642bd7bedabd97ff2f0a902b783e4e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/loader.py","gmt_create":"2026-05-23T15:16:36.228586+08:00","gmt_modified":"2026-05-23T15:16:36.228586+08:00"},{"id":1715,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1de27749fbccdfaf785545657f58d256","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/llm/factory.py","gmt_create":"2026-05-23T15:16:36.229492+08:00","gmt_modified":"2026-05-23T15:16:36.229492+08:00"},{"id":1716,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"290df8332b3d104e5ea8d71dc39315b5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-123","gmt_create":"2026-05-23T15:16:36.230309+08:00","gmt_modified":"2026-05-23T15:16:36.230309+08:00"},{"id":1717,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"85792f0b1e34b5b48b0300aa606ed6e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-56","gmt_create":"2026-05-23T15:16:36.231411+08:00","gmt_modified":"2026-05-23T15:16:36.231411+08:00"},{"id":1718,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-05-23T15:16:36.232293+08:00","gmt_modified":"2026-05-23T15:16:36.232293+08:00"},{"id":1719,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-05-23T15:16:36.233083+08:00","gmt_modified":"2026-05-23T15:16:36.233083+08:00"},{"id":1720,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-05-23T15:16:36.233899+08:00","gmt_modified":"2026-05-23T15:16:36.233899+08:00"},{"id":1721,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-05-23T15:16:36.234893+08:00","gmt_modified":"2026-05-23T15:16:36.234893+08:00"},{"id":1722,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-05-23T15:16:36.235813+08:00","gmt_modified":"2026-05-23T15:16:36.235813+08:00"},{"id":1723,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9630036e63fc15cb81b202cf79671aab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-182","gmt_create":"2026-05-23T15:16:36.236809+08:00","gmt_modified":"2026-05-23T15:16:36.236809+08:00"},{"id":1724,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-05-23T15:16:36.23771+08:00","gmt_modified":"2026-05-23T15:16:36.23771+08:00"},{"id":1725,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-05-23T15:16:36.238575+08:00","gmt_modified":"2026-05-23T15:16:36.238575+08:00"},{"id":1726,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"461200c8ca02024dd32c214c679b9664","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#1-299","gmt_create":"2026-05-23T15:16:36.239366+08:00","gmt_modified":"2026-05-23T15:16:36.239366+08:00"},{"id":1727,"source_id":"13b8f594e7cace5c8a9255dc801dcad8","target_id":"461200c8ca02024dd32c214c679b9664","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-299","gmt_create":"2026-05-23T15:16:36.240866+08:00","gmt_modified":"2026-05-23T15:16:36.240866+08:00"},{"id":1728,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7f44b646183e17098f8ce4d2be931d3e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/deai_agent.py#1-156","gmt_create":"2026-05-23T15:16:36.245637+08:00","gmt_modified":"2026-05-23T15:16:36.245638+08:00"},{"id":1729,"source_id":"750f8d79d83ee910e9d18e8a4fe37e22","target_id":"7f44b646183e17098f8ce4d2be931d3e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-156","gmt_create":"2026-05-23T15:16:36.24631+08:00","gmt_modified":"2026-05-23T15:16:36.24631+08:00"},{"id":1730,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"45778eaa35d92099677ba180f1067905","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/geo_optimizer_agent.py#1-198","gmt_create":"2026-05-23T15:16:36.248542+08:00","gmt_modified":"2026-05-23T15:16:36.248543+08:00"},{"id":1731,"source_id":"7f8c6e94ead45ad9bab8cea9a7be2123","target_id":"45778eaa35d92099677ba180f1067905","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-198","gmt_create":"2026-05-23T15:16:36.248957+08:00","gmt_modified":"2026-05-23T15:16:36.248957+08:00"},{"id":1732,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"74bf1d1b17dff651c44a2f4dc12d7bc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#1-536","gmt_create":"2026-05-23T15:16:36.249504+08:00","gmt_modified":"2026-05-23T15:16:36.249504+08:00"},{"id":1733,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"74bf1d1b17dff651c44a2f4dc12d7bc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-536","gmt_create":"2026-05-23T15:16:36.249909+08:00","gmt_modified":"2026-05-23T15:16:36.249909+08:00"},{"id":1734,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"d8a98dd989912e358f7dbd278e1c5353","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/loader.py#1-283","gmt_create":"2026-05-23T15:16:36.251045+08:00","gmt_modified":"2026-05-23T15:16:36.251045+08:00"},{"id":1735,"source_id":"43642bd7bedabd97ff2f0a902b783e4e","target_id":"d8a98dd989912e358f7dbd278e1c5353","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-283","gmt_create":"2026-05-23T15:16:36.251436+08:00","gmt_modified":"2026-05-23T15:16:36.251436+08:00"},{"id":1736,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"3d0cd79c03fc72299fb184947c5d0d6c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/llm/factory.py#1-66","gmt_create":"2026-05-23T15:16:36.252132+08:00","gmt_modified":"2026-05-23T15:16:36.252132+08:00"},{"id":1737,"source_id":"1de27749fbccdfaf785545657f58d256","target_id":"3d0cd79c03fc72299fb184947c5d0d6c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-66","gmt_create":"2026-05-23T15:16:36.252601+08:00","gmt_modified":"2026-05-23T15:16:36.252601+08:00"},{"id":1738,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5ddf0c8d7b38e4f6126a5d85da1dfeda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#19-123","gmt_create":"2026-05-23T15:16:36.254753+08:00","gmt_modified":"2026-05-23T15:16:36.254754+08:00"},{"id":1739,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"c43dadd2749edf2a89b29068d7644bb9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_content_agents.py#26-54","gmt_create":"2026-05-23T15:16:36.255759+08:00","gmt_modified":"2026-05-23T15:16:36.255759+08:00"},{"id":1740,"source_id":"1eb698126da2b6c95924e3ca32115e3a","target_id":"c43dadd2749edf2a89b29068d7644bb9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-54","gmt_create":"2026-05-23T15:16:36.256483+08:00","gmt_modified":"2026-05-23T15:16:36.256483+08:00"},{"id":1741,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"3251d42aeb8cbe7f90d0e9827fbecdb8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_pipeline_engine.py#148-166","gmt_create":"2026-05-23T15:16:36.25719+08:00","gmt_modified":"2026-05-23T15:16:36.257191+08:00"},{"id":1742,"source_id":"a8bfbe8f5db65abf625c19edc3999a97","target_id":"3251d42aeb8cbe7f90d0e9827fbecdb8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-166","gmt_create":"2026-05-23T15:16:36.257695+08:00","gmt_modified":"2026-05-23T15:16:36.257695+08:00"},{"id":1743,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"9df233ef1be4b95068ed91bf01083ae7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#117-123","gmt_create":"2026-05-23T15:16:36.258257+08:00","gmt_modified":"2026-05-23T15:16:36.258257+08:00"},{"id":1744,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-05-23T15:16:36.260104+08:00","gmt_modified":"2026-05-23T15:16:36.260104+08:00"},{"id":1745,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-05-23T15:16:36.261365+08:00","gmt_modified":"2026-05-23T15:16:36.261365+08:00"},{"id":1746,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#13-43","gmt_create":"2026-05-23T15:16:36.26246+08:00","gmt_modified":"2026-05-23T15:16:36.26246+08:00"},{"id":1747,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"fe70b1fef9f36e73d26d84987e927c7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-86","gmt_create":"2026-05-23T15:16:36.263185+08:00","gmt_modified":"2026-05-23T15:16:36.263186+08:00"},{"id":1748,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"735aef72b4fe6ca4f407e69b7dda8b43","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-78","gmt_create":"2026-05-23T15:16:36.264067+08:00","gmt_modified":"2026-05-23T15:16:36.264067+08:00"},{"id":1749,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8128dd67cf376d2cadf7c2d3831c380a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#23-29","gmt_create":"2026-05-23T15:16:36.264979+08:00","gmt_modified":"2026-05-23T15:16:36.264979+08:00"},{"id":1750,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1721defc3d6206478d3c0692cc821761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#25-104","gmt_create":"2026-05-23T15:16:36.265802+08:00","gmt_modified":"2026-05-23T15:16:36.265802+08:00"},{"id":1751,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"753a437d837246ead62b0e16c6331284","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-69","gmt_create":"2026-05-23T15:16:36.267299+08:00","gmt_modified":"2026-05-23T15:16:36.267299+08:00"},{"id":1752,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#1-104","gmt_create":"2026-05-23T15:16:36.268402+08:00","gmt_modified":"2026-05-23T15:16:36.268402+08:00"},{"id":1753,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-69","gmt_create":"2026-05-23T15:16:36.269648+08:00","gmt_modified":"2026-05-23T15:16:36.269648+08:00"},{"id":1754,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-120","gmt_create":"2026-05-23T15:16:36.271032+08:00","gmt_modified":"2026-05-23T15:16:36.271032+08:00"},{"id":1755,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#122-146","gmt_create":"2026-05-23T15:16:36.272163+08:00","gmt_modified":"2026-05-23T15:16:36.272163+08:00"},{"id":1756,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-05-23T15:16:36.273278+08:00","gmt_modified":"2026-05-23T15:16:36.273279+08:00"},{"id":1757,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"a57acd9da5287c915ac823784a409292","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citation_engine.py#1-127","gmt_create":"2026-05-23T15:16:36.274585+08:00","gmt_modified":"2026-05-23T15:16:36.274586+08:00"},{"id":1758,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"2a4f741f31f62dce8ad63be2e831f520","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#23-93","gmt_create":"2026-05-23T15:16:36.279368+08:00","gmt_modified":"2026-05-23T15:16:36.279368+08:00"},{"id":1759,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"692ac240965eff7e66945aa3c4c270f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_citations.py#1-93","gmt_create":"2026-05-23T15:16:36.281396+08:00","gmt_modified":"2026-05-23T15:16:36.281396+08:00"},{"id":1760,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"32a0a52faca2d8d488e49c63c86075b1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#29-154","gmt_create":"2026-05-23T15:16:36.282984+08:00","gmt_modified":"2026-05-23T15:16:36.282984+08:00"},{"id":1761,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7804331f5f8c1ba5a3b6d9c1ae1c78c1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_queries.py#1-154","gmt_create":"2026-05-23T15:16:36.316134+08:00","gmt_modified":"2026-05-23T15:16:36.316134+08:00"},{"id":1762,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8cdfa09247c1ca69fa5581194d1dc998","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_content_agents.py#75-116","gmt_create":"2026-05-23T15:16:36.317925+08:00","gmt_modified":"2026-05-23T15:16:36.317925+08:00"},{"id":1763,"source_id":"1eb698126da2b6c95924e3ca32115e3a","target_id":"8cdfa09247c1ca69fa5581194d1dc998","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 75-116","gmt_create":"2026-05-23T15:16:36.318326+08:00","gmt_modified":"2026-05-23T15:16:36.318326+08:00"},{"id":1764,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"4d43427ff0dc504c0665bd3e3f86d68c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_content_agents.py#200-236","gmt_create":"2026-05-23T15:16:36.319097+08:00","gmt_modified":"2026-05-23T15:16:36.319097+08:00"},{"id":1765,"source_id":"1eb698126da2b6c95924e3ca32115e3a","target_id":"4d43427ff0dc504c0665bd3e3f86d68c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 200-236","gmt_create":"2026-05-23T15:16:36.319906+08:00","gmt_modified":"2026-05-23T15:16:36.319906+08:00"},{"id":1766,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7ec53d0bb9dd7a59cedbd4d3865fddf8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_content_agents.py#268-320","gmt_create":"2026-05-23T15:16:36.320562+08:00","gmt_modified":"2026-05-23T15:16:36.320562+08:00"},{"id":1767,"source_id":"1eb698126da2b6c95924e3ca32115e3a","target_id":"7ec53d0bb9dd7a59cedbd4d3865fddf8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 268-320","gmt_create":"2026-05-23T15:16:36.320984+08:00","gmt_modified":"2026-05-23T15:16:36.320984+08:00"},{"id":1768,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"67b04d8d66c36c9362f3c42260f08d77","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_content_agents.py#1-358","gmt_create":"2026-05-23T15:16:36.321507+08:00","gmt_modified":"2026-05-23T15:16:36.321507+08:00"},{"id":1769,"source_id":"1eb698126da2b6c95924e3ca32115e3a","target_id":"67b04d8d66c36c9362f3c42260f08d77","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-358","gmt_create":"2026-05-23T15:16:36.321902+08:00","gmt_modified":"2026-05-23T15:16:36.321902+08:00"},{"id":1770,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"a29fa4c505649339b1a61e2bd730e05a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_llm_provider.py#24-67","gmt_create":"2026-05-23T15:16:36.32363+08:00","gmt_modified":"2026-05-23T15:16:36.32363+08:00"},{"id":1771,"source_id":"ff5699698ead454bb1137030cf21c533","target_id":"a29fa4c505649339b1a61e2bd730e05a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-67","gmt_create":"2026-05-23T15:16:36.324115+08:00","gmt_modified":"2026-05-23T15:16:36.324115+08:00"},{"id":1772,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"892c4889ccac1ebb4f9871633c633fb0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_llm_provider.py#94-153","gmt_create":"2026-05-23T15:16:36.32487+08:00","gmt_modified":"2026-05-23T15:16:36.32487+08:00"},{"id":1773,"source_id":"ff5699698ead454bb1137030cf21c533","target_id":"892c4889ccac1ebb4f9871633c633fb0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 94-153","gmt_create":"2026-05-23T15:16:36.326005+08:00","gmt_modified":"2026-05-23T15:16:36.326005+08:00"},{"id":1774,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"5a90244fc04639f59621ea190b395d53","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_llm_provider.py#200-204","gmt_create":"2026-05-23T15:16:36.32715+08:00","gmt_modified":"2026-05-23T15:16:36.32715+08:00"},{"id":1775,"source_id":"ff5699698ead454bb1137030cf21c533","target_id":"5a90244fc04639f59621ea190b395d53","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 200-204","gmt_create":"2026-05-23T15:16:36.327777+08:00","gmt_modified":"2026-05-23T15:16:36.327777+08:00"},{"id":1776,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7a5c445db631fd099bd752645fe46eeb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/llm/factory.py#8-66","gmt_create":"2026-05-23T15:16:36.328343+08:00","gmt_modified":"2026-05-23T15:16:36.328343+08:00"},{"id":1777,"source_id":"1de27749fbccdfaf785545657f58d256","target_id":"7a5c445db631fd099bd752645fe46eeb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-66","gmt_create":"2026-05-23T15:16:36.328713+08:00","gmt_modified":"2026-05-23T15:16:36.328713+08:00"},{"id":1778,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"470e94b38cfbc9bfa40075043a5ff609","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_llm_provider.py#1-205","gmt_create":"2026-05-23T15:16:36.329291+08:00","gmt_modified":"2026-05-23T15:16:36.329291+08:00"},{"id":1779,"source_id":"ff5699698ead454bb1137030cf21c533","target_id":"470e94b38cfbc9bfa40075043a5ff609","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-205","gmt_create":"2026-05-23T15:16:36.329648+08:00","gmt_modified":"2026-05-23T15:16:36.329648+08:00"},{"id":1780,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"e2014a3633197a028b389f084f136010","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_pipeline_engine.py#55-98","gmt_create":"2026-05-23T15:16:36.330763+08:00","gmt_modified":"2026-05-23T15:16:36.330763+08:00"},{"id":1781,"source_id":"a8bfbe8f5db65abf625c19edc3999a97","target_id":"e2014a3633197a028b389f084f136010","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 55-98","gmt_create":"2026-05-23T15:16:36.331132+08:00","gmt_modified":"2026-05-23T15:16:36.331132+08:00"},{"id":1782,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"4d80ca6fa9f1355807471a059213113a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_pipeline_engine.py#148-223","gmt_create":"2026-05-23T15:16:36.331648+08:00","gmt_modified":"2026-05-23T15:16:36.331648+08:00"},{"id":1783,"source_id":"a8bfbe8f5db65abf625c19edc3999a97","target_id":"4d80ca6fa9f1355807471a059213113a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-223","gmt_create":"2026-05-23T15:16:36.33201+08:00","gmt_modified":"2026-05-23T15:16:36.33201+08:00"},{"id":1784,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1c16d98271c83e4d1bf7759d6eff90e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/loader.py#41-134","gmt_create":"2026-05-23T15:16:36.332547+08:00","gmt_modified":"2026-05-23T15:16:36.332547+08:00"},{"id":1785,"source_id":"43642bd7bedabd97ff2f0a902b783e4e","target_id":"1c16d98271c83e4d1bf7759d6eff90e7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 41-134","gmt_create":"2026-05-23T15:16:36.332928+08:00","gmt_modified":"2026-05-23T15:16:36.332928+08:00"},{"id":1786,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"32e64c6a06a68a4c10f248296033c62e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#31-176","gmt_create":"2026-05-23T15:16:36.333572+08:00","gmt_modified":"2026-05-23T15:16:36.333572+08:00"},{"id":1787,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"32e64c6a06a68a4c10f248296033c62e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-176","gmt_create":"2026-05-23T15:16:36.334143+08:00","gmt_modified":"2026-05-23T15:16:36.334143+08:00"},{"id":1788,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"a593c13b0e0e255b16b161d69fcd4c09","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_pipeline_engine.py#1-255","gmt_create":"2026-05-23T15:16:36.334754+08:00","gmt_modified":"2026-05-23T15:16:36.334754+08:00"},{"id":1789,"source_id":"a8bfbe8f5db65abf625c19edc3999a97","target_id":"a593c13b0e0e255b16b161d69fcd4c09","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-255","gmt_create":"2026-05-23T15:16:36.33547+08:00","gmt_modified":"2026-05-23T15:16:36.33547+08:00"},{"id":1790,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7a0c4604142743b83dfb37f2ff1aa3e8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/tests/test_integration/test_full_flow.py#94-223","gmt_create":"2026-05-23T15:16:36.337164+08:00","gmt_modified":"2026-05-23T15:16:36.337164+08:00"},{"id":1791,"source_id":"af7c8d3b4ba659f1bd8c4989b5ed7a62","target_id":"7a0c4604142743b83dfb37f2ff1aa3e8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 94-223","gmt_create":"2026-05-23T15:16:36.337647+08:00","gmt_modified":"2026-05-23T15:16:36.337647+08:00"},{"id":1792,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"3548385bba6b1c5a95d40191fbb95fc4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/tests/test_integration/test_full_flow.py#228-298","gmt_create":"2026-05-23T15:16:36.338255+08:00","gmt_modified":"2026-05-23T15:16:36.338255+08:00"},{"id":1793,"source_id":"af7c8d3b4ba659f1bd8c4989b5ed7a62","target_id":"3548385bba6b1c5a95d40191fbb95fc4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 228-298","gmt_create":"2026-05-23T15:16:36.338678+08:00","gmt_modified":"2026-05-23T15:16:36.338678+08:00"},{"id":1794,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"4c439b670fff499e1277c271ed2e3598","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/tests/test_integration/test_full_flow.py#1-322","gmt_create":"2026-05-23T15:16:36.339576+08:00","gmt_modified":"2026-05-23T15:16:36.339576+08:00"},{"id":1795,"source_id":"af7c8d3b4ba659f1bd8c4989b5ed7a62","target_id":"4c439b670fff499e1277c271ed2e3598","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-322","gmt_create":"2026-05-23T15:16:36.340019+08:00","gmt_modified":"2026-05-23T15:16:36.340019+08:00"},{"id":1796,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"3a6e1b738967bf8cc651e57f48e2e126","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#83-126","gmt_create":"2026-05-23T15:16:36.340705+08:00","gmt_modified":"2026-05-23T15:16:36.340705+08:00"},{"id":1797,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"b1afd377757f1d0e9bdf87edfff3ad88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#131-186","gmt_create":"2026-05-23T15:16:36.341571+08:00","gmt_modified":"2026-05-23T15:16:36.341571+08:00"},{"id":1798,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"de05ec7eed033e432991e5a88e1b5a06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#192-222","gmt_create":"2026-05-23T15:16:36.343423+08:00","gmt_modified":"2026-05-23T15:16:36.343423+08:00"},{"id":1799,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"7fd61a451248b6b129299d6246f711c7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#228-296","gmt_create":"2026-05-23T15:16:36.344609+08:00","gmt_modified":"2026-05-23T15:16:36.344609+08:00"},{"id":1800,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"53eedffff456a566fa7b0cecc7169f56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_business_flow.py#1-441","gmt_create":"2026-05-23T15:16:36.345412+08:00","gmt_modified":"2026-05-23T15:16:36.345412+08:00"},{"id":1801,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"906f7a8288e38d4244211f3f538fe7b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#27-182","gmt_create":"2026-05-23T15:16:36.346167+08:00","gmt_modified":"2026-05-23T15:16:36.346167+08:00"},{"id":1802,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"1647ee2066de2ae59ba8cf88e33c5e02","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_scheduler.py#1-123","gmt_create":"2026-05-23T15:16:36.346937+08:00","gmt_modified":"2026-05-23T15:16:36.346937+08:00"},{"id":1803,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:17:24.156756+08:00","gmt_modified":"2026-05-23T15:17:24.156756+08:00"},{"id":1804,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:17:24.15738+08:00","gmt_modified":"2026-05-23T15:17:24.15738+08:00"},{"id":1805,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-05-23T15:17:24.157856+08:00","gmt_modified":"2026-05-23T15:17:24.157856+08:00"},{"id":1806,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:17:24.158305+08:00","gmt_modified":"2026-05-23T15:17:24.158305+08:00"},{"id":1807,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-05-23T15:17:24.158712+08:00","gmt_modified":"2026-05-23T15:17:24.158712+08:00"},{"id":1808,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5386144bf3c668c6fa14481c0d85a214","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/subscriptions.py","gmt_create":"2026-05-23T15:17:24.159304+08:00","gmt_modified":"2026-05-23T15:17:24.159304+08:00"},{"id":1809,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f26740f2a1532b38c816663a4f665dbf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/admin.py","gmt_create":"2026-05-23T15:17:24.161122+08:00","gmt_modified":"2026-05-23T15:17:24.161123+08:00"},{"id":1810,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6a9387dd3885cf4d27bce3db87fd61c7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/agents.py","gmt_create":"2026-05-23T15:17:24.161871+08:00","gmt_modified":"2026-05-23T15:17:24.161871+08:00"},{"id":1811,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9af41884bf42d6e175163e89f663a479","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/analytics.py","gmt_create":"2026-05-23T15:17:24.162493+08:00","gmt_modified":"2026-05-23T15:17:24.162493+08:00"},{"id":1812,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9c224bb80474867f8ded674babaa6e11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/lifecycle.py","gmt_create":"2026-05-23T15:17:24.163341+08:00","gmt_modified":"2026-05-23T15:17:24.163341+08:00"},{"id":1813,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"63953ee6b39f159a61963104ac06f283","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/knowledge.py","gmt_create":"2026-05-23T15:17:24.164229+08:00","gmt_modified":"2026-05-23T15:17:24.164229+08:00"},{"id":1814,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-05-23T15:17:24.164778+08:00","gmt_modified":"2026-05-23T15:17:24.164778+08:00"},{"id":1815,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5883a8ef4fc156d76b71ffdb5ecdf232","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/rate_limit.py","gmt_create":"2026-05-23T15:17:24.165716+08:00","gmt_modified":"2026-05-23T15:17:24.165716+08:00"},{"id":1816,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-05-23T15:17:24.166436+08:00","gmt_modified":"2026-05-23T15:17:24.166436+08:00"},{"id":1817,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-05-23T15:17:24.166929+08:00","gmt_modified":"2026-05-23T15:17:24.166929+08:00"},{"id":1818,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-05-23T15:17:24.167341+08:00","gmt_modified":"2026-05-23T15:17:24.167341+08:00"},{"id":1819,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5013cbe89f1c6f03533eb218400cedb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/subscription.py","gmt_create":"2026-05-23T15:17:24.167751+08:00","gmt_modified":"2026-05-23T15:17:24.167752+08:00"},{"id":1820,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6940047dd4c29a8a219b1b50e358f7c1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/analytics.py","gmt_create":"2026-05-23T15:17:24.168313+08:00","gmt_modified":"2026-05-23T15:17:24.168313+08:00"},{"id":1821,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"952c887faf6f91370b174bd4e1ad6e00","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/lifecycle.py","gmt_create":"2026-05-23T15:17:24.169203+08:00","gmt_modified":"2026-05-23T15:17:24.169203+08:00"},{"id":1822,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ed4505205a22ba55c7d4a83b0b24eaa4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/knowledge.py","gmt_create":"2026-05-23T15:17:24.170114+08:00","gmt_modified":"2026-05-23T15:17:24.170114+08:00"},{"id":1823,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:17:24.171119+08:00","gmt_modified":"2026-05-23T15:17:24.171119+08:00"},{"id":1824,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-05-23T15:17:24.172532+08:00","gmt_modified":"2026-05-23T15:17:24.172533+08:00"},{"id":1825,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-05-23T15:17:24.173154+08:00","gmt_modified":"2026-05-23T15:17:24.173154+08:00"},{"id":1826,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b250fc6c32106a7f3e0c3ad152dfc097","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/subscription.py","gmt_create":"2026-05-23T15:17:24.173811+08:00","gmt_modified":"2026-05-23T15:17:24.173811+08:00"},{"id":1827,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3809c5ab912511e0e093ba02a4fc918f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/admin.py","gmt_create":"2026-05-23T15:17:24.174428+08:00","gmt_modified":"2026-05-23T15:17:24.174428+08:00"},{"id":1828,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a0c569cd2355079f9f4045a198ddcadc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/analytics/insights.py","gmt_create":"2026-05-23T15:17:24.175148+08:00","gmt_modified":"2026-05-23T15:17:24.175148+08:00"},{"id":1829,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"984d67382822ff587452a79f89e0d336","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/analytics/tracker.py","gmt_create":"2026-05-23T15:17:24.175886+08:00","gmt_modified":"2026-05-23T15:17:24.175886+08:00"},{"id":1830,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"45c9d96513947cae445aaaf8b58b4266","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/knowledge/rag_service.py","gmt_create":"2026-05-23T15:17:24.176407+08:00","gmt_modified":"2026-05-23T15:17:24.176407+08:00"},{"id":1831,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3b13f3fa9b6316b23cfd01d740a85b81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/knowledge/chunker.py","gmt_create":"2026-05-23T15:17:24.178905+08:00","gmt_modified":"2026-05-23T15:17:24.178905+08:00"},{"id":1832,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"aaa9ce5fdaad8eaa6887e8c079e0b7af","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/knowledge/embedder.py","gmt_create":"2026-05-23T15:17:24.17971+08:00","gmt_modified":"2026-05-23T15:17:24.17971+08:00"},{"id":1833,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"000702af850583bb79fec57f7fd1fcca","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/knowledge/retriever.py","gmt_create":"2026-05-23T15:17:24.180374+08:00","gmt_modified":"2026-05-23T15:17:24.180374+08:00"},{"id":1834,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:17:24.18144+08:00","gmt_modified":"2026-05-23T15:17:24.18144+08:00"},{"id":1835,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-05-23T15:17:24.182209+08:00","gmt_modified":"2026-05-23T15:17:24.18221+08:00"},{"id":1836,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:17:24.183087+08:00","gmt_modified":"2026-05-23T15:17:24.183087+08:00"},{"id":1837,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-05-23T15:17:24.184037+08:00","gmt_modified":"2026-05-23T15:17:24.184037+08:00"},{"id":1838,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-05-23T15:17:24.18506+08:00","gmt_modified":"2026-05-23T15:17:24.18506+08:00"},{"id":1839,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-05-23T15:17:24.185602+08:00","gmt_modified":"2026-05-23T15:17:24.185602+08:00"},{"id":1840,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"aa6cf63a65ebf46a29606af91112eb7b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/agent.py","gmt_create":"2026-05-23T15:17:24.186064+08:00","gmt_modified":"2026-05-23T15:17:24.186064+08:00"},{"id":1841,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"97cfe961cb7386b4022a51706ae8f5dd","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/lifecycle.py","gmt_create":"2026-05-23T15:17:24.186929+08:00","gmt_modified":"2026-05-23T15:17:24.186929+08:00"},{"id":1842,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4774aadaa8ace576601bdaa8d3e11f74","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/knowledge.py","gmt_create":"2026-05-23T15:17:24.187568+08:00","gmt_modified":"2026-05-23T15:17:24.187568+08:00"},{"id":1843,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"0fcc0fe680a7ca8b8c7f4d579b77aeec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#12-78","gmt_create":"2026-05-23T15:17:24.188555+08:00","gmt_modified":"2026-05-23T15:17:24.188555+08:00"},{"id":1844,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"10d3948b1394ffa0110796edfa0bfc25","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#30","gmt_create":"2026-05-23T15:17:24.204464+08:00","gmt_modified":"2026-05-23T15:17:24.204464+08:00"},{"id":1845,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"0a5c3d0a239107364b77b52d4ff33454","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/agents.py#29","gmt_create":"2026-05-23T15:17:24.20616+08:00","gmt_modified":"2026-05-23T15:17:24.20616+08:00"},{"id":1846,"source_id":"6a9387dd3885cf4d27bce3db87fd61c7","target_id":"0a5c3d0a239107364b77b52d4ff33454","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29","gmt_create":"2026-05-23T15:17:24.206732+08:00","gmt_modified":"2026-05-23T15:17:24.206732+08:00"},{"id":1847,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6c9ecb8d32dfd5ce9b2dc95f1a110d97","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/analytics.py#26","gmt_create":"2026-05-23T15:17:24.207346+08:00","gmt_modified":"2026-05-23T15:17:24.207346+08:00"},{"id":1848,"source_id":"9af41884bf42d6e175163e89f663a479","target_id":"6c9ecb8d32dfd5ce9b2dc95f1a110d97","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26","gmt_create":"2026-05-23T15:17:24.207877+08:00","gmt_modified":"2026-05-23T15:17:24.207877+08:00"},{"id":1849,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6242be39e66058ce4f2dd93974e98599","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#24","gmt_create":"2026-05-23T15:17:24.208801+08:00","gmt_modified":"2026-05-23T15:17:24.208801+08:00"},{"id":1850,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"6242be39e66058ce4f2dd93974e98599","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24","gmt_create":"2026-05-23T15:17:24.210225+08:00","gmt_modified":"2026-05-23T15:17:24.210225+08:00"},{"id":1851,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3dde6ad029645735cef7c4edf22b28c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#38","gmt_create":"2026-05-23T15:17:24.213173+08:00","gmt_modified":"2026-05-23T15:17:24.213173+08:00"},{"id":1852,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"3dde6ad029645735cef7c4edf22b28c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38","gmt_create":"2026-05-23T15:17:24.2143+08:00","gmt_modified":"2026-05-23T15:17:24.214301+08:00"},{"id":1853,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f240c1067c223a019ba05b0fbd718aa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-84","gmt_create":"2026-05-23T15:17:24.215324+08:00","gmt_modified":"2026-05-23T15:17:24.215324+08:00"},{"id":1854,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"d6ebce8c7d9e9de127486400670ebed0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#39-84","gmt_create":"2026-05-23T15:17:24.216598+08:00","gmt_modified":"2026-05-23T15:17:24.216598+08:00"},{"id":1855,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-115","gmt_create":"2026-05-23T15:17:24.21734+08:00","gmt_modified":"2026-05-23T15:17:24.21734+08:00"},{"id":1856,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c7cbd948815aa81602e95e7e469a2b80","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/agents.py#66-299","gmt_create":"2026-05-23T15:17:24.218834+08:00","gmt_modified":"2026-05-23T15:17:24.218834+08:00"},{"id":1857,"source_id":"6a9387dd3885cf4d27bce3db87fd61c7","target_id":"c7cbd948815aa81602e95e7e469a2b80","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 66-299","gmt_create":"2026-05-23T15:17:24.219687+08:00","gmt_modified":"2026-05-23T15:17:24.219687+08:00"},{"id":1858,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c666a867c1b927bcc12241a45e84cd71","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/analytics.py#47-243","gmt_create":"2026-05-23T15:17:24.22048+08:00","gmt_modified":"2026-05-23T15:17:24.220481+08:00"},{"id":1859,"source_id":"9af41884bf42d6e175163e89f663a479","target_id":"c666a867c1b927bcc12241a45e84cd71","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-243","gmt_create":"2026-05-23T15:17:24.221074+08:00","gmt_modified":"2026-05-23T15:17:24.221074+08:00"},{"id":1860,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"196c325b93526e566ba9f2560a82c2ac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#85-297","gmt_create":"2026-05-23T15:17:24.222051+08:00","gmt_modified":"2026-05-23T15:17:24.222051+08:00"},{"id":1861,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"196c325b93526e566ba9f2560a82c2ac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 85-297","gmt_create":"2026-05-23T15:17:24.222588+08:00","gmt_modified":"2026-05-23T15:17:24.222589+08:00"},{"id":1862,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f617a59447265c18ad5d4c79e9db8e12","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#81-502","gmt_create":"2026-05-23T15:17:24.223422+08:00","gmt_modified":"2026-05-23T15:17:24.223422+08:00"},{"id":1863,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"f617a59447265c18ad5d4c79e9db8e12","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 81-502","gmt_create":"2026-05-23T15:17:24.224138+08:00","gmt_modified":"2026-05-23T15:17:24.224139+08:00"},{"id":1864,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#10-83","gmt_create":"2026-05-23T15:17:24.224761+08:00","gmt_modified":"2026-05-23T15:17:24.224761+08:00"},{"id":1865,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"2db9940a42c91fc92f23595491ea93d1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#67-78","gmt_create":"2026-05-23T15:17:24.225488+08:00","gmt_modified":"2026-05-23T15:17:24.225488+08:00"},{"id":1866,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"bcdf50f6234651cb9863ab210e6473e5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-42","gmt_create":"2026-05-23T15:17:24.230136+08:00","gmt_modified":"2026-05-23T15:17:24.230136+08:00"},{"id":1867,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6df0277c2486b148fa26c2682dbdaa4c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-68","gmt_create":"2026-05-23T15:17:24.231867+08:00","gmt_modified":"2026-05-23T15:17:24.231867+08:00"},{"id":1868,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"5ea5f192d580031ffe57e1582b70c67e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-123","gmt_create":"2026-05-23T15:17:24.232789+08:00","gmt_modified":"2026-05-23T15:17:24.23279+08:00"},{"id":1869,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"fe4a793f16cd4e12b56253c0a6d53ae0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#24-359","gmt_create":"2026-05-23T15:17:24.234569+08:00","gmt_modified":"2026-05-23T15:17:24.234569+08:00"},{"id":1870,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"68fbb2bd365f96a98ea187a9738c4460","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-57","gmt_create":"2026-05-23T15:17:24.235656+08:00","gmt_modified":"2026-05-23T15:17:24.235656+08:00"},{"id":1871,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#7-34","gmt_create":"2026-05-23T15:17:24.239144+08:00","gmt_modified":"2026-05-23T15:17:24.239144+08:00"},{"id":1872,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-05-23T15:17:24.241451+08:00","gmt_modified":"2026-05-23T15:17:24.241451+08:00"},{"id":1873,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ae9de874df4a46f4197b6c157c25ec6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#15-85","gmt_create":"2026-05-23T15:17:24.242206+08:00","gmt_modified":"2026-05-23T15:17:24.242206+08:00"},{"id":1874,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"69118807690ef351a9de910414d5e676","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#11-94","gmt_create":"2026-05-23T15:17:24.247111+08:00","gmt_modified":"2026-05-23T15:17:24.247111+08:00"},{"id":1875,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-05-23T15:17:24.249091+08:00","gmt_modified":"2026-05-23T15:17:24.249092+08:00"},{"id":1876,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b0777c7da17be89abb333c81c0dcf349","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-261","gmt_create":"2026-05-23T15:17:24.250307+08:00","gmt_modified":"2026-05-23T15:17:24.250307+08:00"},{"id":1877,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c066a8d4bffabed87a2e38ccad81c107","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#25-77","gmt_create":"2026-05-23T15:17:24.251358+08:00","gmt_modified":"2026-05-23T15:17:24.251358+08:00"},{"id":1878,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"26288877e8e1f6c4ff5aca12610b0218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-50","gmt_create":"2026-05-23T15:17:24.252188+08:00","gmt_modified":"2026-05-23T15:17:24.252188+08:00"},{"id":1879,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"44f9c9f195e096efbd6c6a6f97880944","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#51-75","gmt_create":"2026-05-23T15:17:24.253763+08:00","gmt_modified":"2026-05-23T15:17:24.253763+08:00"},{"id":1880,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"cbe8ffc1cfb98ac79c7659e968191837","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#343-466","gmt_create":"2026-05-23T15:17:24.255124+08:00","gmt_modified":"2026-05-23T15:17:24.255124+08:00"},{"id":1881,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#18-75","gmt_create":"2026-05-23T15:17:24.256276+08:00","gmt_modified":"2026-05-23T15:17:24.256276+08:00"},{"id":1882,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"97f9b6149bd43feb0f69cf2582ab6305","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#85-117","gmt_create":"2026-05-23T15:17:24.25803+08:00","gmt_modified":"2026-05-23T15:17:24.25803+08:00"},{"id":1883,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ec3ed02cad3cd8af4bacb5c978273092","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#26-77","gmt_create":"2026-05-23T15:17:24.259391+08:00","gmt_modified":"2026-05-23T15:17:24.259391+08:00"},{"id":1884,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ce4de96353f8f81ca825173ddbec1150","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/subscription.py#12-41","gmt_create":"2026-05-23T15:17:24.262322+08:00","gmt_modified":"2026-05-23T15:17:24.262323+08:00"},{"id":1885,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a87a1a7c1723518159d5818c197996cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#56-155","gmt_create":"2026-05-23T15:17:24.263733+08:00","gmt_modified":"2026-05-23T15:17:24.263733+08:00"},{"id":1886,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"0e4bc0a539e0ccc6832031bdaf1eb1ca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-45","gmt_create":"2026-05-23T15:17:24.265191+08:00","gmt_modified":"2026-05-23T15:17:24.265191+08:00"},{"id":1887,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f7314a4515e822cba6f37d7a8f1970f3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-46","gmt_create":"2026-05-23T15:17:24.266934+08:00","gmt_modified":"2026-05-23T15:17:24.266934+08:00"},{"id":1888,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-108","gmt_create":"2026-05-23T15:17:24.268355+08:00","gmt_modified":"2026-05-23T15:17:24.268355+08:00"},{"id":1889,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-188","gmt_create":"2026-05-23T15:17:24.269431+08:00","gmt_modified":"2026-05-23T15:17:24.269431+08:00"},{"id":1890,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ffb5c89d546d3895e7ac0ed320a6ed90","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/agents.py#186-222","gmt_create":"2026-05-23T15:17:24.270579+08:00","gmt_modified":"2026-05-23T15:17:24.270579+08:00"},{"id":1891,"source_id":"6a9387dd3885cf4d27bce3db87fd61c7","target_id":"ffb5c89d546d3895e7ac0ed320a6ed90","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 186-222","gmt_create":"2026-05-23T15:17:24.271154+08:00","gmt_modified":"2026-05-23T15:17:24.271154+08:00"},{"id":1892,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"e6fe884abc694714e2eb8bf1be27d72b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/agent.py#98-155","gmt_create":"2026-05-23T15:17:24.27219+08:00","gmt_modified":"2026-05-23T15:17:24.27219+08:00"},{"id":1893,"source_id":"aa6cf63a65ebf46a29606af91112eb7b","target_id":"e6fe884abc694714e2eb8bf1be27d72b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 98-155","gmt_create":"2026-05-23T15:17:24.272858+08:00","gmt_modified":"2026-05-23T15:17:24.272859+08:00"},{"id":1894,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ebc123c07512c5d5aeb1011d228a895c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/agent.py#12-206","gmt_create":"2026-05-23T15:17:24.274033+08:00","gmt_modified":"2026-05-23T15:17:24.274034+08:00"},{"id":1895,"source_id":"aa6cf63a65ebf46a29606af91112eb7b","target_id":"ebc123c07512c5d5aeb1011d228a895c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-206","gmt_create":"2026-05-23T15:17:24.274595+08:00","gmt_modified":"2026-05-23T15:17:24.274595+08:00"},{"id":1896,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"9cbf60c1b6ff2f8c74be2f168f4f44eb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/analytics.py#47-60","gmt_create":"2026-05-23T15:17:24.275162+08:00","gmt_modified":"2026-05-23T15:17:24.275162+08:00"},{"id":1897,"source_id":"9af41884bf42d6e175163e89f663a479","target_id":"9cbf60c1b6ff2f8c74be2f168f4f44eb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-60","gmt_create":"2026-05-23T15:17:24.275621+08:00","gmt_modified":"2026-05-23T15:17:24.275621+08:00"},{"id":1898,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"eb865aa7324cbb6c6ec83cf884c36b98","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/analytics.py#206-212","gmt_create":"2026-05-23T15:17:24.277851+08:00","gmt_modified":"2026-05-23T15:17:24.277851+08:00"},{"id":1899,"source_id":"9af41884bf42d6e175163e89f663a479","target_id":"eb865aa7324cbb6c6ec83cf884c36b98","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 206-212","gmt_create":"2026-05-23T15:17:24.278515+08:00","gmt_modified":"2026-05-23T15:17:24.278515+08:00"},{"id":1900,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"68580333c31256edc20b45d90197222c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/analytics.py#14-145","gmt_create":"2026-05-23T15:17:24.280338+08:00","gmt_modified":"2026-05-23T15:17:24.280338+08:00"},{"id":1901,"source_id":"6940047dd4c29a8a219b1b50e358f7c1","target_id":"68580333c31256edc20b45d90197222c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14-145","gmt_create":"2026-05-23T15:17:24.280921+08:00","gmt_modified":"2026-05-23T15:17:24.280922+08:00"},{"id":1902,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"98d6d7fe81309b5f48907ff2c96bd9e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#190-230","gmt_create":"2026-05-23T15:17:24.281728+08:00","gmt_modified":"2026-05-23T15:17:24.281728+08:00"},{"id":1903,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"98d6d7fe81309b5f48907ff2c96bd9e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 190-230","gmt_create":"2026-05-23T15:17:24.282759+08:00","gmt_modified":"2026-05-23T15:17:24.282759+08:00"},{"id":1904,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4d98c570e47fa5aa35c93cc23d9a9531","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/lifecycle.py#9-68","gmt_create":"2026-05-23T15:17:24.284357+08:00","gmt_modified":"2026-05-23T15:17:24.284357+08:00"},{"id":1905,"source_id":"952c887faf6f91370b174bd4e1ad6e00","target_id":"4d98c570e47fa5aa35c93cc23d9a9531","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-68","gmt_create":"2026-05-23T15:17:24.284879+08:00","gmt_modified":"2026-05-23T15:17:24.284879+08:00"},{"id":1906,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"6a2a5a7cb69cc0e72c2e90e1d9e48037","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/lifecycle.py#12-92","gmt_create":"2026-05-23T15:17:24.285676+08:00","gmt_modified":"2026-05-23T15:17:24.285676+08:00"},{"id":1907,"source_id":"97cfe961cb7386b4022a51706ae8f5dd","target_id":"6a2a5a7cb69cc0e72c2e90e1d9e48037","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-92","gmt_create":"2026-05-23T15:17:24.286407+08:00","gmt_modified":"2026-05-23T15:17:24.286408+08:00"},{"id":1908,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f38b21f300a72d77625c203e8d9e5916","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#424-501","gmt_create":"2026-05-23T15:17:24.288543+08:00","gmt_modified":"2026-05-23T15:17:24.288543+08:00"},{"id":1909,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"f38b21f300a72d77625c203e8d9e5916","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 424-501","gmt_create":"2026-05-23T15:17:24.289121+08:00","gmt_modified":"2026-05-23T15:17:24.289121+08:00"},{"id":1910,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"02ee224326bf5a0307c63b44ccb270ac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/knowledge.py#9-77","gmt_create":"2026-05-23T15:17:24.290606+08:00","gmt_modified":"2026-05-23T15:17:24.290606+08:00"},{"id":1911,"source_id":"ed4505205a22ba55c7d4a83b0b24eaa4","target_id":"02ee224326bf5a0307c63b44ccb270ac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-77","gmt_create":"2026-05-23T15:17:24.291254+08:00","gmt_modified":"2026-05-23T15:17:24.291254+08:00"},{"id":1912,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f043b2767c713f94381e9f7154cd904a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/knowledge.py#22-213","gmt_create":"2026-05-23T15:17:24.292253+08:00","gmt_modified":"2026-05-23T15:17:24.292253+08:00"},{"id":1913,"source_id":"4774aadaa8ace576601bdaa8d3e11f74","target_id":"f043b2767c713f94381e9f7154cd904a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-213","gmt_create":"2026-05-23T15:17:24.292799+08:00","gmt_modified":"2026-05-23T15:17:24.292799+08:00"},{"id":1914,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ef31f4aa4fbd1b6ff76eba467b757a04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#34-69","gmt_create":"2026-05-23T15:17:24.295615+08:00","gmt_modified":"2026-05-23T15:17:24.295616+08:00"},{"id":1915,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-05-23T15:17:24.297824+08:00","gmt_modified":"2026-05-23T15:17:24.297824+08:00"},{"id":1916,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-05-23T15:17:24.299265+08:00","gmt_modified":"2026-05-23T15:17:24.299265+08:00"},{"id":1917,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-05-23T15:17:24.300537+08:00","gmt_modified":"2026-05-23T15:17:24.300537+08:00"},{"id":1918,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-05-23T15:17:24.301612+08:00","gmt_modified":"2026-05-23T15:17:24.301612+08:00"},{"id":1919,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-05-23T15:17:24.3024+08:00","gmt_modified":"2026-05-23T15:17:24.3024+08:00"},{"id":1920,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"1a2657244414b5681afded9565a86422","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#35-40","gmt_create":"2026-05-23T15:17:24.305671+08:00","gmt_modified":"2026-05-23T15:17:24.305671+08:00"},{"id":1921,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"acd5a29be2bdd4ae251e10ca266ffe13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#43-48","gmt_create":"2026-05-23T15:17:24.306445+08:00","gmt_modified":"2026-05-23T15:17:24.306446+08:00"},{"id":1922,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"27a5e2dd1d197b2e3a45be41c57a6183","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#35","gmt_create":"2026-05-23T15:17:24.30719+08:00","gmt_modified":"2026-05-23T15:17:24.307191+08:00"},{"id":1923,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"c43e8fc0c04c5ed2db7798d99c8c77b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#34","gmt_create":"2026-05-23T15:17:24.308001+08:00","gmt_modified":"2026-05-23T15:17:24.308002+08:00"},{"id":1924,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3a7201f4564dbcf35c5771f1b5d58cb6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#46-50","gmt_create":"2026-05-23T15:17:24.308792+08:00","gmt_modified":"2026-05-23T15:17:24.308792+08:00"},{"id":1925,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a50f983ec39bac67dff5df80f6dad837","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#59-60","gmt_create":"2026-05-23T15:17:24.312167+08:00","gmt_modified":"2026-05-23T15:17:24.312167+08:00"},{"id":1926,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"55f1628f1ab6f323710e367e12146b1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#67-71","gmt_create":"2026-05-23T15:17:24.313833+08:00","gmt_modified":"2026-05-23T15:17:24.313833+08:00"},{"id":1927,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"39c3dbe67ab2ae74446fe6a118bd8738","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#25-29","gmt_create":"2026-05-23T15:17:24.315656+08:00","gmt_modified":"2026-05-23T15:17:24.315656+08:00"},{"id":1928,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"68d937267aab2509edc0c7b67e1b5ef6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#53-57","gmt_create":"2026-05-23T15:17:24.316691+08:00","gmt_modified":"2026-05-23T15:17:24.316691+08:00"},{"id":1929,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3d0bf5a05f6a7d2b8b12bb91e8f93642","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#22-25","gmt_create":"2026-05-23T15:17:24.317568+08:00","gmt_modified":"2026-05-23T15:17:24.317568+08:00"},{"id":1930,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"934240d46ff47296dae2c8aef650b86f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/agents.py#84-88","gmt_create":"2026-05-23T15:17:24.318329+08:00","gmt_modified":"2026-05-23T15:17:24.31833+08:00"},{"id":1931,"source_id":"6a9387dd3885cf4d27bce3db87fd61c7","target_id":"934240d46ff47296dae2c8aef650b86f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 84-88","gmt_create":"2026-05-23T15:17:24.320157+08:00","gmt_modified":"2026-05-23T15:17:24.320157+08:00"},{"id":1932,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"be2989f88e1e49d5282ec7353c9c4e89","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/analytics.py#36-40","gmt_create":"2026-05-23T15:17:24.321292+08:00","gmt_modified":"2026-05-23T15:17:24.321292+08:00"},{"id":1933,"source_id":"9af41884bf42d6e175163e89f663a479","target_id":"be2989f88e1e49d5282ec7353c9c4e89","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-40","gmt_create":"2026-05-23T15:17:24.322188+08:00","gmt_modified":"2026-05-23T15:17:24.322188+08:00"},{"id":1934,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"3b33430ff6a3ac8b10af49dc35af8231","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#146","gmt_create":"2026-05-23T15:17:24.323054+08:00","gmt_modified":"2026-05-23T15:17:24.323054+08:00"},{"id":1935,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"3b33430ff6a3ac8b10af49dc35af8231","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 146","gmt_create":"2026-05-23T15:17:24.323656+08:00","gmt_modified":"2026-05-23T15:17:24.323656+08:00"},{"id":1936,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"59b4deade567af54c91f1a162e57b5be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#92-96","gmt_create":"2026-05-23T15:17:24.324417+08:00","gmt_modified":"2026-05-23T15:17:24.324417+08:00"},{"id":1937,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"59b4deade567af54c91f1a162e57b5be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 92-96","gmt_create":"2026-05-23T15:17:24.324896+08:00","gmt_modified":"2026-05-23T15:17:24.324896+08:00"},{"id":1938,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"a9c1b0716ae36af22fce6148c2e40ce5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#47-49","gmt_create":"2026-05-23T15:17:24.327641+08:00","gmt_modified":"2026-05-23T15:17:24.327641+08:00"},{"id":1939,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-05-23T15:18:41.125269+08:00","gmt_modified":"2026-05-23T15:18:41.12527+08:00"},{"id":1940,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-05-23T15:18:41.126121+08:00","gmt_modified":"2026-05-23T15:18:41.126122+08:00"},{"id":1941,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:18:41.126809+08:00","gmt_modified":"2026-05-23T15:18:41.126809+08:00"},{"id":1942,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-05-23T15:18:41.128865+08:00","gmt_modified":"2026-05-23T15:18:41.128866+08:00"},{"id":1943,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"5e414f2ef9b69e55e00ab15f85b9291a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/Dockerfile","gmt_create":"2026-05-23T15:18:41.13011+08:00","gmt_modified":"2026-05-23T15:18:41.13011+08:00"},{"id":1944,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-05-23T15:18:41.131281+08:00","gmt_modified":"2026-05-23T15:18:41.131281+08:00"},{"id":1945,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic.ini","gmt_create":"2026-05-23T15:18:41.132282+08:00","gmt_modified":"2026-05-23T15:18:41.132282+08:00"},{"id":1946,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:18:41.133446+08:00","gmt_modified":"2026-05-23T15:18:41.133447+08:00"},{"id":1947,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"fb8af100a06778e1fbdac4790a3ed0a9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tsconfig.json","gmt_create":"2026-05-23T15:18:41.134065+08:00","gmt_modified":"2026-05-23T15:18:41.134066+08:00"},{"id":1948,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-05-23T15:18:41.134649+08:00","gmt_modified":"2026-05-23T15:18:41.134649+08:00"},{"id":1949,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4d9b59c294a0aac5e300b3de715eb226","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/.eslintrc.json","gmt_create":"2026-05-23T15:18:41.135265+08:00","gmt_modified":"2026-05-23T15:18:41.135265+08:00"},{"id":1950,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"0ef1efea889dba3e1f299626df479571","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/conftest.py","gmt_create":"2026-05-23T15:18:41.136046+08:00","gmt_modified":"2026-05-23T15:18:41.136046+08:00"},{"id":1951,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:18:41.136696+08:00","gmt_modified":"2026-05-23T15:18:41.136697+08:00"},{"id":1952,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-05-23T15:18:41.137419+08:00","gmt_modified":"2026-05-23T15:18:41.13742+08:00"},{"id":1953,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-05-23T15:18:41.138044+08:00","gmt_modified":"2026-05-23T15:18:41.138044+08:00"},{"id":1954,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"48a560c49d2b21da327c036ec2934b96","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: README.md","gmt_create":"2026-05-23T15:18:41.138715+08:00","gmt_modified":"2026-05-23T15:18:41.138715+08:00"},{"id":1955,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"3a1e34b542590c287768482d964dc7d5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/03-development/coding-standards.md","gmt_create":"2026-05-23T15:18:41.139302+08:00","gmt_modified":"2026-05-23T15:18:41.139302+08:00"},{"id":1956,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"53d01851ef76ade6cb41a3cbe140676f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/03-development/dev-guide.md","gmt_create":"2026-05-23T15:18:41.139886+08:00","gmt_modified":"2026-05-23T15:18:41.139887+08:00"},{"id":1957,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"21e6700955fa049df458cee6020cf073","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/05-deployment/deployment-guide.md","gmt_create":"2026-05-23T15:18:41.140569+08:00","gmt_modified":"2026-05-23T15:18:41.140569+08:00"},{"id":1958,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"b0db309ae449a2a435fc77103ca76955","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/04-testing/test-strategy.md","gmt_create":"2026-05-23T15:18:41.14129+08:00","gmt_modified":"2026-05-23T15:18:41.141291+08:00"},{"id":1959,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"974abe01413cc7a8a4898621e0b0779e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/03-development/tdd-workflow.md","gmt_create":"2026-05-23T15:18:41.141882+08:00","gmt_modified":"2026-05-23T15:18:41.141883+08:00"},{"id":1960,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"01a3a8e0d02ddfa2e64837790ba231fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docs/00-project/tech-stack.md","gmt_create":"2026-05-23T15:18:41.142482+08:00","gmt_modified":"2026-05-23T15:18:41.142482+08:00"},{"id":1961,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-05-23T15:18:41.14327+08:00","gmt_modified":"2026-05-23T15:18:41.14327+08:00"},{"id":1962,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"01a0c4b40819965823b56e9da858c024","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/Dockerfile#1-15","gmt_create":"2026-05-23T15:18:41.14466+08:00","gmt_modified":"2026-05-23T15:18:41.144661+08:00"},{"id":1963,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"412695e5de2014514a8f62f98c573656","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#1-41","gmt_create":"2026-05-23T15:18:41.146114+08:00","gmt_modified":"2026-05-23T15:18:41.146114+08:00"},{"id":1964,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6171fd1748ad5189394ba670000e7e75","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-45","gmt_create":"2026-05-23T15:18:41.147542+08:00","gmt_modified":"2026-05-23T15:18:41.147543+08:00"},{"id":1965,"source_id":"aaf5bce6be82d2f947bfa5c1806de452","target_id":"6171fd1748ad5189394ba670000e7e75","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-45","gmt_create":"2026-05-23T15:18:41.148436+08:00","gmt_modified":"2026-05-23T15:18:41.148436+08:00"},{"id":1966,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"00502fc9ffc15147665f96f056735d74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-42","gmt_create":"2026-05-23T15:18:41.150097+08:00","gmt_modified":"2026-05-23T15:18:41.150097+08:00"},{"id":1967,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"00502fc9ffc15147665f96f056735d74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-42","gmt_create":"2026-05-23T15:18:41.150919+08:00","gmt_modified":"2026-05-23T15:18:41.150919+08:00"},{"id":1968,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-05-23T15:18:41.15193+08:00","gmt_modified":"2026-05-23T15:18:41.15193+08:00"},{"id":1969,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"dd36901ce62b8cc1d66667dcdc45e637","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-46","gmt_create":"2026-05-23T15:18:41.15309+08:00","gmt_modified":"2026-05-23T15:18:41.15309+08:00"},{"id":1970,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"dd36901ce62b8cc1d66667dcdc45e637","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-46","gmt_create":"2026-05-23T15:18:41.153678+08:00","gmt_modified":"2026-05-23T15:18:41.153678+08:00"},{"id":1971,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"13f6ca76349ef86ae756bb519f122bc5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#1-150","gmt_create":"2026-05-23T15:18:41.15511+08:00","gmt_modified":"2026-05-23T15:18:41.15511+08:00"},{"id":1972,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"74abd6612105c29b67178fa9dbd04b61","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tsconfig.json#1-27","gmt_create":"2026-05-23T15:18:41.165191+08:00","gmt_modified":"2026-05-23T15:18:41.165191+08:00"},{"id":1973,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"36ca3ba8293eaed314a7628b0272e957","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/.eslintrc.json#1-14","gmt_create":"2026-05-23T15:18:41.167086+08:00","gmt_modified":"2026-05-23T15:18:41.167086+08:00"},{"id":1974,"source_id":"4d9b59c294a0aac5e300b3de715eb226","target_id":"36ca3ba8293eaed314a7628b0272e957","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-05-23T15:18:41.167599+08:00","gmt_modified":"2026-05-23T15:18:41.167599+08:00"},{"id":1975,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"89d70e5f89be23a229e3ee59982b8e6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-57","gmt_create":"2026-05-23T15:18:41.168439+08:00","gmt_modified":"2026-05-23T15:18:41.168439+08:00"},{"id":1976,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9482f4f6279a4f636b77e69b8273b996","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#86-114","gmt_create":"2026-05-23T15:18:41.169649+08:00","gmt_modified":"2026-05-23T15:18:41.169649+08:00"},{"id":1977,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"397b266f19a1addebdf6c32db71ae77f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#1-71","gmt_create":"2026-05-23T15:18:41.170634+08:00","gmt_modified":"2026-05-23T15:18:41.170635+08:00"},{"id":1978,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"b55a164add5a8fec2ef0e489f7234829","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-47","gmt_create":"2026-05-23T15:18:41.171613+08:00","gmt_modified":"2026-05-23T15:18:41.171613+08:00"},{"id":1979,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"03b024618527c930185a98873f353b45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#12-18","gmt_create":"2026-05-23T15:18:41.17271+08:00","gmt_modified":"2026-05-23T15:18:41.172711+08:00"},{"id":1980,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"03b024618527c930185a98873f353b45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-18","gmt_create":"2026-05-23T15:18:41.173408+08:00","gmt_modified":"2026-05-23T15:18:41.173408+08:00"},{"id":1981,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c25b39830f3b7734da975acc7f214666","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#31-33","gmt_create":"2026-05-23T15:18:41.174222+08:00","gmt_modified":"2026-05-23T15:18:41.174222+08:00"},{"id":1982,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4c9d362ecce8e796e6f14850def049b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#4-20","gmt_create":"2026-05-23T15:18:41.175392+08:00","gmt_modified":"2026-05-23T15:18:41.175392+08:00"},{"id":1983,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"d5827be2cfbe41c8177660ae877e93a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#22-34","gmt_create":"2026-05-23T15:18:41.176895+08:00","gmt_modified":"2026-05-23T15:18:41.176895+08:00"},{"id":1984,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"03a65cdcfc173217d12ad8a417f8f033","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-21","gmt_create":"2026-05-23T15:18:41.17848+08:00","gmt_modified":"2026-05-23T15:18:41.17848+08:00"},{"id":1985,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-05-23T15:18:41.180294+08:00","gmt_modified":"2026-05-23T15:18:41.180294+08:00"},{"id":1986,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"3365fa8db33d43bab1d0a614e8af3a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#45-47","gmt_create":"2026-05-23T15:18:41.18154+08:00","gmt_modified":"2026-05-23T15:18:41.18154+08:00"},{"id":1987,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"4aad38dfc00a0877bd965c3d0b3c280c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#7-34","gmt_create":"2026-05-23T15:18:41.18289+08:00","gmt_modified":"2026-05-23T15:18:41.18289+08:00"},{"id":1988,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-05-23T15:18:41.183973+08:00","gmt_modified":"2026-05-23T15:18:41.183973+08:00"},{"id":1989,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-05-23T15:18:41.185191+08:00","gmt_modified":"2026-05-23T15:18:41.185191+08:00"},{"id":1990,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#1-34","gmt_create":"2026-05-23T15:18:41.186137+08:00","gmt_modified":"2026-05-23T15:18:41.186138+08:00"},{"id":1991,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-05-23T15:18:41.187004+08:00","gmt_modified":"2026-05-23T15:18:41.187004+08:00"},{"id":1992,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"1693d293c428ed4a66bd90519a1bbad5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#12-13","gmt_create":"2026-05-23T15:18:41.188741+08:00","gmt_modified":"2026-05-23T15:18:41.188741+08:00"},{"id":1993,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"1693d293c428ed4a66bd90519a1bbad5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-13","gmt_create":"2026-05-23T15:18:41.189245+08:00","gmt_modified":"2026-05-23T15:18:41.189245+08:00"},{"id":1994,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"37bbab6e4f16db7eac6eee9d05e80e46","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: README.md#1-3","gmt_create":"2026-05-23T15:18:41.192525+08:00","gmt_modified":"2026-05-23T15:18:41.192525+08:00"},{"id":1995,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c4f552eaa67bc052a06af7e5399d954c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#9-46","gmt_create":"2026-05-23T15:18:41.193775+08:00","gmt_modified":"2026-05-23T15:18:41.193775+08:00"},{"id":1996,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"c4f552eaa67bc052a06af7e5399d954c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-46","gmt_create":"2026-05-23T15:18:41.195066+08:00","gmt_modified":"2026-05-23T15:18:41.195066+08:00"},{"id":1997,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"db1c839ece4f3899017126c9b5b36016","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/03-development/coding-standards.md#1-29","gmt_create":"2026-05-23T15:18:41.200058+08:00","gmt_modified":"2026-05-23T15:18:41.200058+08:00"},{"id":1998,"source_id":"3a1e34b542590c287768482d964dc7d5","target_id":"db1c839ece4f3899017126c9b5b36016","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-05-23T15:18:41.2015+08:00","gmt_modified":"2026-05-23T15:18:41.2015+08:00"},{"id":1999,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"9efa352ff057d696763b5eca047c0ca1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/03-development/dev-guide.md#1-32","gmt_create":"2026-05-23T15:18:41.204125+08:00","gmt_modified":"2026-05-23T15:18:41.204125+08:00"},{"id":2000,"source_id":"53d01851ef76ade6cb41a3cbe140676f","target_id":"9efa352ff057d696763b5eca047c0ca1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-32","gmt_create":"2026-05-23T15:18:41.20481+08:00","gmt_modified":"2026-05-23T15:18:41.204811+08:00"},{"id":2001,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"10a5c824715b3c199eb40e1531c64150","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/03-development/tdd-workflow.md#1-583","gmt_create":"2026-05-23T15:18:41.207218+08:00","gmt_modified":"2026-05-23T15:18:41.207218+08:00"},{"id":2002,"source_id":"974abe01413cc7a8a4898621e0b0779e","target_id":"10a5c824715b3c199eb40e1531c64150","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-583","gmt_create":"2026-05-23T15:18:41.208007+08:00","gmt_modified":"2026-05-23T15:18:41.208008+08:00"},{"id":2003,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"a47a364b551a984436d38cc17a272ef5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/04-testing/test-strategy.md#1-33","gmt_create":"2026-05-23T15:18:41.209182+08:00","gmt_modified":"2026-05-23T15:18:41.209183+08:00"},{"id":2004,"source_id":"b0db309ae449a2a435fc77103ca76955","target_id":"a47a364b551a984436d38cc17a272ef5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-33","gmt_create":"2026-05-23T15:18:41.21001+08:00","gmt_modified":"2026-05-23T15:18:41.21001+08:00"},{"id":2005,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"6d2bbc04de724a57683b6d1af6f76e5b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/05-deployment/deployment-guide.md#1-32","gmt_create":"2026-05-23T15:18:41.210974+08:00","gmt_modified":"2026-05-23T15:18:41.210974+08:00"},{"id":2006,"source_id":"21e6700955fa049df458cee6020cf073","target_id":"6d2bbc04de724a57683b6d1af6f76e5b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-32","gmt_create":"2026-05-23T15:18:41.214582+08:00","gmt_modified":"2026-05-23T15:18:41.214582+08:00"},{"id":2007,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"bf363deac5ef38c8dc80c73b862e730b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#4-34","gmt_create":"2026-05-23T15:18:41.216958+08:00","gmt_modified":"2026-05-23T15:18:41.216958+08:00"},{"id":2008,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"c6e94075e5f689bfa2fe16f8cf965203","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/conftest.py#19-50","gmt_create":"2026-05-23T15:18:41.218379+08:00","gmt_modified":"2026-05-23T15:18:41.218379+08:00"},{"id":2009,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"1a78f5574add6d07a1d7c947dba3f23d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#115-150","gmt_create":"2026-05-23T15:18:41.219483+08:00","gmt_modified":"2026-05-23T15:18:41.219484+08:00"},{"id":2010,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"f6810849c947471a4b45d7ca01ec8c5f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#5-9","gmt_create":"2026-05-23T15:18:41.220597+08:00","gmt_modified":"2026-05-23T15:18:41.220597+08:00"},{"id":2011,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"67f5802e0fa695697eb6eeb1d1071448","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docs/00-project/tech-stack.md#1-71","gmt_create":"2026-05-23T15:18:41.221486+08:00","gmt_modified":"2026-05-23T15:18:41.221486+08:00"},{"id":2012,"source_id":"01a3a8e0d02ddfa2e64837790ba231fa","target_id":"67f5802e0fa695697eb6eeb1d1071448","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-71","gmt_create":"2026-05-23T15:18:41.22238+08:00","gmt_modified":"2026-05-23T15:18:41.22238+08:00"},{"id":2013,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-05-23T15:19:23.554788+08:00","gmt_modified":"2026-05-23T15:19:23.554788+08:00"},{"id":2014,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-05-23T15:19:23.555831+08:00","gmt_modified":"2026-05-23T15:19:23.555831+08:00"},{"id":2015,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:19:23.556658+08:00","gmt_modified":"2026-05-23T15:19:23.556658+08:00"},{"id":2016,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-05-23T15:19:23.572491+08:00","gmt_modified":"2026-05-23T15:19:23.572491+08:00"},{"id":2017,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-05-23T15:19:23.573626+08:00","gmt_modified":"2026-05-23T15:19:23.573626+08:00"},{"id":2018,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-05-23T15:19:23.574254+08:00","gmt_modified":"2026-05-23T15:19:23.574254+08:00"},{"id":2019,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"97cfe961cb7386b4022a51706ae8f5dd","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/lifecycle.py","gmt_create":"2026-05-23T15:19:23.57478+08:00","gmt_modified":"2026-05-23T15:19:23.57478+08:00"},{"id":2020,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"68688ca664c7df5d64153200455dd7f6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/analytics.py","gmt_create":"2026-05-23T15:19:23.577281+08:00","gmt_modified":"2026-05-23T15:19:23.577282+08:00"},{"id":2021,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9bad7097cce919cde648d435f673bac1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/alert.py","gmt_create":"2026-05-23T15:19:23.578795+08:00","gmt_modified":"2026-05-23T15:19:23.578795+08:00"},{"id":2022,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4774aadaa8ace576601bdaa8d3e11f74","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/knowledge.py","gmt_create":"2026-05-23T15:19:23.579569+08:00","gmt_modified":"2026-05-23T15:19:23.579569+08:00"},{"id":2023,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"99fe1b288fd41daa86c2dfbab819abf0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/__init__.py","gmt_create":"2026-05-23T15:19:23.580288+08:00","gmt_modified":"2026-05-23T15:19:23.580289+08:00"},{"id":2024,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"a680d4819f5da57fe9fa0e6bc708f380","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/env.py","gmt_create":"2026-05-23T15:19:23.580755+08:00","gmt_modified":"2026-05-23T15:19:23.580755+08:00"},{"id":2025,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-05-23T15:19:23.581175+08:00","gmt_modified":"2026-05-23T15:19:23.581175+08:00"},{"id":2026,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f6e6948dd0cdd3894bd9928b21feb979","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","gmt_create":"2026-05-23T15:19:23.581588+08:00","gmt_modified":"2026-05-23T15:19:23.581588+08:00"},{"id":2027,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"b0cb6810919f64006be7aa66b2b76a61","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-05-23T15:19:23.582209+08:00","gmt_modified":"2026-05-23T15:19:23.58221+08:00"},{"id":2028,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"daab5d62bc9559915da6c4bd52dcec91","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","gmt_create":"2026-05-23T15:19:23.582692+08:00","gmt_modified":"2026-05-23T15:19:23.582692+08:00"},{"id":2029,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"22a884dd0b02fa904cd2808646d4aeca","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","gmt_create":"2026-05-23T15:19:23.583198+08:00","gmt_modified":"2026-05-23T15:19:23.583198+08:00"},{"id":2030,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"e029becbf7babac61765f6a1790e1d48","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py","gmt_create":"2026-05-23T15:19:23.583893+08:00","gmt_modified":"2026-05-23T15:19:23.583894+08:00"},{"id":2031,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"0c2c0c0ef594628c812c0adda8b914ea","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py","gmt_create":"2026-05-23T15:19:23.584455+08:00","gmt_modified":"2026-05-23T15:19:23.584455+08:00"},{"id":2032,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic.ini","gmt_create":"2026-05-23T15:19:23.585197+08:00","gmt_modified":"2026-05-23T15:19:23.585197+08:00"},{"id":2033,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:19:23.585749+08:00","gmt_modified":"2026-05-23T15:19:23.585749+08:00"},{"id":2034,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-05-23T15:19:23.586422+08:00","gmt_modified":"2026-05-23T15:19:23.586422+08:00"},{"id":2035,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-05-23T15:19:23.587606+08:00","gmt_modified":"2026-05-23T15:19:23.587606+08:00"},{"id":2036,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-05-23T15:19:23.588128+08:00","gmt_modified":"2026-05-23T15:19:23.588128+08:00"},{"id":2037,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:19:23.588692+08:00","gmt_modified":"2026-05-23T15:19:23.588692+08:00"},{"id":2038,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-05-23T15:19:23.589291+08:00","gmt_modified":"2026-05-23T15:19:23.589291+08:00"},{"id":2039,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:19:23.59001+08:00","gmt_modified":"2026-05-23T15:19:23.59001+08:00"},{"id":2040,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:19:23.590586+08:00","gmt_modified":"2026-05-23T15:19:23.590586+08:00"},{"id":2041,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-05-23T15:19:23.591167+08:00","gmt_modified":"2026-05-23T15:19:23.591167+08:00"},{"id":2042,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9c224bb80474867f8ded674babaa6e11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/lifecycle.py","gmt_create":"2026-05-23T15:19:23.591703+08:00","gmt_modified":"2026-05-23T15:19:23.591704+08:00"},{"id":2043,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9af41884bf42d6e175163e89f663a479","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/analytics.py","gmt_create":"2026-05-23T15:19:23.59225+08:00","gmt_modified":"2026-05-23T15:19:23.59225+08:00"},{"id":2044,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"80f3f2a6213e0002803247e1c51233be","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/alerts.py","gmt_create":"2026-05-23T15:19:23.595593+08:00","gmt_modified":"2026-05-23T15:19:23.595594+08:00"},{"id":2045,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"63953ee6b39f159a61963104ac06f283","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/knowledge.py","gmt_create":"2026-05-23T15:19:23.596908+08:00","gmt_modified":"2026-05-23T15:19:23.596908+08:00"},{"id":2046,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ea655c6d147bc98beb42955d437260cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-23","gmt_create":"2026-05-23T15:19:23.599053+08:00","gmt_modified":"2026-05-23T15:19:23.599053+08:00"},{"id":2047,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-05-23T15:19:23.600626+08:00","gmt_modified":"2026-05-23T15:19:23.600627+08:00"},{"id":2048,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1f8d26b6a5da49d89d95bb13c7ace2c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-48","gmt_create":"2026-05-23T15:19:23.601368+08:00","gmt_modified":"2026-05-23T15:19:23.601368+08:00"},{"id":2049,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"87eaeed0bc611204a7529b148ae846e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/lifecycle.py#1-92","gmt_create":"2026-05-23T15:19:23.602071+08:00","gmt_modified":"2026-05-23T15:19:23.602071+08:00"},{"id":2050,"source_id":"97cfe961cb7386b4022a51706ae8f5dd","target_id":"87eaeed0bc611204a7529b148ae846e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-92","gmt_create":"2026-05-23T15:19:23.602675+08:00","gmt_modified":"2026-05-23T15:19:23.602675+08:00"},{"id":2051,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"790fb08a04a977bb97a81ea19d785777","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/analytics.py#1-64","gmt_create":"2026-05-23T15:19:23.603748+08:00","gmt_modified":"2026-05-23T15:19:23.603748+08:00"},{"id":2052,"source_id":"68688ca664c7df5d64153200455dd7f6","target_id":"790fb08a04a977bb97a81ea19d785777","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-64","gmt_create":"2026-05-23T15:19:23.6044+08:00","gmt_modified":"2026-05-23T15:19:23.604401+08:00"},{"id":2053,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7bf4a8a5aa73c1704f76f4947a1a327a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/alert.py#1-75","gmt_create":"2026-05-23T15:19:23.605762+08:00","gmt_modified":"2026-05-23T15:19:23.605762+08:00"},{"id":2054,"source_id":"9bad7097cce919cde648d435f673bac1","target_id":"7bf4a8a5aa73c1704f76f4947a1a327a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-75","gmt_create":"2026-05-23T15:19:23.606279+08:00","gmt_modified":"2026-05-23T15:19:23.606279+08:00"},{"id":2055,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9b03c2a2c7f00f40338248fa6d6f5c8b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/knowledge.py#1-213","gmt_create":"2026-05-23T15:19:23.607048+08:00","gmt_modified":"2026-05-23T15:19:23.607048+08:00"},{"id":2056,"source_id":"4774aadaa8ace576601bdaa8d3e11f74","target_id":"9b03c2a2c7f00f40338248fa6d6f5c8b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-213","gmt_create":"2026-05-23T15:19:23.607557+08:00","gmt_modified":"2026-05-23T15:19:23.607557+08:00"},{"id":2057,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"211463f5b49610f09594c40c0a235943","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#1-89","gmt_create":"2026-05-23T15:19:23.609634+08:00","gmt_modified":"2026-05-23T15:19:23.609634+08:00"},{"id":2058,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-05-23T15:19:23.611743+08:00","gmt_modified":"2026-05-23T15:19:23.611743+08:00"},{"id":2059,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"afe4138895492c26aac5c0120ef46cd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/__init__.py#1-14","gmt_create":"2026-05-23T15:19:23.616111+08:00","gmt_modified":"2026-05-23T15:19:23.616111+08:00"},{"id":2060,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"98cc82f62b83678f06a33cf9231ecdf8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#1-128","gmt_create":"2026-05-23T15:19:23.617406+08:00","gmt_modified":"2026-05-23T15:19:23.617406+08:00"},{"id":2061,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"e1aabd52989e47806fb997157381e1cf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#1-37","gmt_create":"2026-05-23T15:19:23.61884+08:00","gmt_modified":"2026-05-23T15:19:23.61884+08:00"},{"id":2062,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c8f2dbcb7475bd189a34c7061ea46c6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#1-41","gmt_create":"2026-05-23T15:19:23.619785+08:00","gmt_modified":"2026-05-23T15:19:23.619785+08:00"},{"id":2063,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d15e1f6c18afa7505178062959fe7333","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#1-398","gmt_create":"2026-05-23T15:19:23.620822+08:00","gmt_modified":"2026-05-23T15:19:23.620822+08:00"},{"id":2064,"source_id":"daab5d62bc9559915da6c4bd52dcec91","target_id":"d15e1f6c18afa7505178062959fe7333","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-398","gmt_create":"2026-05-23T15:19:23.621339+08:00","gmt_modified":"2026-05-23T15:19:23.621339+08:00"},{"id":2065,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"762a2f675ceac5ab98af9a601f886b64","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#1-125","gmt_create":"2026-05-23T15:19:23.623307+08:00","gmt_modified":"2026-05-23T15:19:23.623307+08:00"},{"id":2066,"source_id":"0c2c0c0ef594628c812c0adda8b914ea","target_id":"762a2f675ceac5ab98af9a601f886b64","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-125","gmt_create":"2026-05-23T15:19:23.623741+08:00","gmt_modified":"2026-05-23T15:19:23.623741+08:00"},{"id":2067,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"2df394b949344fe9ab2c77227b91a836","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#1-86","gmt_create":"2026-05-23T15:19:23.624366+08:00","gmt_modified":"2026-05-23T15:19:23.624366+08:00"},{"id":2068,"source_id":"22a884dd0b02fa904cd2808646d4aeca","target_id":"2df394b949344fe9ab2c77227b91a836","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-86","gmt_create":"2026-05-23T15:19:23.626309+08:00","gmt_modified":"2026-05-23T15:19:23.626309+08:00"},{"id":2069,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"0dc739a646e968be4ef81f8d6f73172f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#1-224","gmt_create":"2026-05-23T15:19:23.627322+08:00","gmt_modified":"2026-05-23T15:19:23.627322+08:00"},{"id":2070,"source_id":"e029becbf7babac61765f6a1790e1d48","target_id":"0dc739a646e968be4ef81f8d6f73172f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-224","gmt_create":"2026-05-23T15:19:23.62795+08:00","gmt_modified":"2026-05-23T15:19:23.627951+08:00"},{"id":2071,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-130","gmt_create":"2026-05-23T15:19:23.628703+08:00","gmt_modified":"2026-05-23T15:19:23.628703+08:00"},{"id":2072,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"5d2836286eb7d4eb6039b004a9744d26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-429","gmt_create":"2026-05-23T15:19:23.629487+08:00","gmt_modified":"2026-05-23T15:19:23.629487+08:00"},{"id":2073,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"08c1475254a5bc8877ff29a895de3b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-175","gmt_create":"2026-05-23T15:19:23.630346+08:00","gmt_modified":"2026-05-23T15:19:23.630346+08:00"},{"id":2074,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f5978358d04c3c917d9ca5044c7f36fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-48","gmt_create":"2026-05-23T15:19:23.63281+08:00","gmt_modified":"2026-05-23T15:19:23.63281+08:00"},{"id":2075,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"6a2a5a7cb69cc0e72c2e90e1d9e48037","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/lifecycle.py#12-92","gmt_create":"2026-05-23T15:19:23.633688+08:00","gmt_modified":"2026-05-23T15:19:23.633688+08:00"},{"id":2076,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"867308b1867163b86fcf5da125bff7bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/analytics.py#9-64","gmt_create":"2026-05-23T15:19:23.634567+08:00","gmt_modified":"2026-05-23T15:19:23.634567+08:00"},{"id":2077,"source_id":"68688ca664c7df5d64153200455dd7f6","target_id":"867308b1867163b86fcf5da125bff7bd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-64","gmt_create":"2026-05-23T15:19:23.635182+08:00","gmt_modified":"2026-05-23T15:19:23.635183+08:00"},{"id":2078,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7bb1fe5eea543a455c000decbf835a87","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/alert.py#24-75","gmt_create":"2026-05-23T15:19:23.636116+08:00","gmt_modified":"2026-05-23T15:19:23.636117+08:00"},{"id":2079,"source_id":"9bad7097cce919cde648d435f673bac1","target_id":"7bb1fe5eea543a455c000decbf835a87","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-75","gmt_create":"2026-05-23T15:19:23.636556+08:00","gmt_modified":"2026-05-23T15:19:23.636556+08:00"},{"id":2080,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"f043b2767c713f94381e9f7154cd904a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/knowledge.py#22-213","gmt_create":"2026-05-23T15:19:23.637182+08:00","gmt_modified":"2026-05-23T15:19:23.637182+08:00"},{"id":2081,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ac77e4875817616194b7b5997d4fb1ae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#57-94","gmt_create":"2026-05-23T15:19:23.64098+08:00","gmt_modified":"2026-05-23T15:19:23.64098+08:00"},{"id":2082,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"0e57efd98dacc85da21f995980371ee4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py#21-37","gmt_create":"2026-05-23T15:19:23.643443+08:00","gmt_modified":"2026-05-23T15:19:23.643443+08:00"},{"id":2083,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"675ab6c1ae510ca753b5e966b7b6a10c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py#21-41","gmt_create":"2026-05-23T15:19:23.645994+08:00","gmt_modified":"2026-05-23T15:19:23.645994+08:00"},{"id":2084,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"14d45085df87325a1a8a05e5a7306ea9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#24-398","gmt_create":"2026-05-23T15:19:23.647263+08:00","gmt_modified":"2026-05-23T15:19:23.647263+08:00"},{"id":2085,"source_id":"daab5d62bc9559915da6c4bd52dcec91","target_id":"14d45085df87325a1a8a05e5a7306ea9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-398","gmt_create":"2026-05-23T15:19:23.647719+08:00","gmt_modified":"2026-05-23T15:19:23.647719+08:00"},{"id":2086,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ab4062f7b12bddc89c8a6ecb5716ec22","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#24-125","gmt_create":"2026-05-23T15:19:23.648321+08:00","gmt_modified":"2026-05-23T15:19:23.648321+08:00"},{"id":2087,"source_id":"0c2c0c0ef594628c812c0adda8b914ea","target_id":"ab4062f7b12bddc89c8a6ecb5716ec22","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-125","gmt_create":"2026-05-23T15:19:23.6488+08:00","gmt_modified":"2026-05-23T15:19:23.6488+08:00"},{"id":2088,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d8c1ac7c70dcfce3893bb34ccad2ea86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#24-86","gmt_create":"2026-05-23T15:19:23.649406+08:00","gmt_modified":"2026-05-23T15:19:23.649406+08:00"},{"id":2089,"source_id":"22a884dd0b02fa904cd2808646d4aeca","target_id":"d8c1ac7c70dcfce3893bb34ccad2ea86","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-86","gmt_create":"2026-05-23T15:19:23.650058+08:00","gmt_modified":"2026-05-23T15:19:23.650058+08:00"},{"id":2090,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"3f54e06cbaf0717d01fb0f4cb7294795","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#30-224","gmt_create":"2026-05-23T15:19:23.651039+08:00","gmt_modified":"2026-05-23T15:19:23.65104+08:00"},{"id":2091,"source_id":"e029becbf7babac61765f6a1790e1d48","target_id":"3f54e06cbaf0717d01fb0f4cb7294795","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-224","gmt_create":"2026-05-23T15:19:23.651691+08:00","gmt_modified":"2026-05-23T15:19:23.651691+08:00"},{"id":2092,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d34337b9ff77246979252d2fd8fb8018","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#33-88","gmt_create":"2026-05-23T15:19:23.662049+08:00","gmt_modified":"2026-05-23T15:19:23.662049+08:00"},{"id":2093,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4d11ddf7abb8076d81b30c4315786f9a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#21-128","gmt_create":"2026-05-23T15:19:23.664087+08:00","gmt_modified":"2026-05-23T15:19:23.664087+08:00"},{"id":2094,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"948aa417b68df80b5de0cfdb37e5455e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py#21-398","gmt_create":"2026-05-23T15:19:23.665869+08:00","gmt_modified":"2026-05-23T15:19:23.665869+08:00"},{"id":2095,"source_id":"daab5d62bc9559915da6c4bd52dcec91","target_id":"948aa417b68df80b5de0cfdb37e5455e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-398","gmt_create":"2026-05-23T15:19:23.666599+08:00","gmt_modified":"2026-05-23T15:19:23.666599+08:00"},{"id":2096,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"96de5ca994afbb0cc75f2b0d419d69f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py#21-86","gmt_create":"2026-05-23T15:19:23.667775+08:00","gmt_modified":"2026-05-23T15:19:23.66778+08:00"},{"id":2097,"source_id":"22a884dd0b02fa904cd2808646d4aeca","target_id":"96de5ca994afbb0cc75f2b0d419d69f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-86","gmt_create":"2026-05-23T15:19:23.669265+08:00","gmt_modified":"2026-05-23T15:19:23.669265+08:00"},{"id":2098,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"5f830240a0d18e5b3718cd8cabebed6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py#21-224","gmt_create":"2026-05-23T15:19:23.669953+08:00","gmt_modified":"2026-05-23T15:19:23.669953+08:00"},{"id":2099,"source_id":"e029becbf7babac61765f6a1790e1d48","target_id":"5f830240a0d18e5b3718cd8cabebed6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-224","gmt_create":"2026-05-23T15:19:23.670664+08:00","gmt_modified":"2026-05-23T15:19:23.670665+08:00"},{"id":2100,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"4a7611bf0d84c8d44518673bbe5af6ad","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py#20-125","gmt_create":"2026-05-23T15:19:23.671643+08:00","gmt_modified":"2026-05-23T15:19:23.671643+08:00"},{"id":2101,"source_id":"0c2c0c0ef594628c812c0adda8b914ea","target_id":"4a7611bf0d84c8d44518673bbe5af6ad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-125","gmt_create":"2026-05-23T15:19:23.672211+08:00","gmt_modified":"2026-05-23T15:19:23.672211+08:00"},{"id":2102,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"eb63042f04a22f9a67bd498df1684d20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/versions/488d0bd5ab01_initial_migration.py#36-111","gmt_create":"2026-05-23T15:19:23.680639+08:00","gmt_modified":"2026-05-23T15:19:23.680639+08:00"},{"id":2103,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-05-23T15:19:23.68471+08:00","gmt_modified":"2026-05-23T15:19:23.684711+08:00"},{"id":2104,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c651c7ad6747a92ee96eabb2eb82afdd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#12-18","gmt_create":"2026-05-23T15:19:23.686051+08:00","gmt_modified":"2026-05-23T15:19:23.686051+08:00"},{"id":2105,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7dae7237f11c5100bf7889c105193cf6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#12-32","gmt_create":"2026-05-23T15:19:23.687784+08:00","gmt_modified":"2026-05-23T15:19:23.687784+08:00"},{"id":2106,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"dd01eee487298a28e950f6345196f1d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#30-79","gmt_create":"2026-05-23T15:19:23.688917+08:00","gmt_modified":"2026-05-23T15:19:23.688917+08:00"},{"id":2107,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"fe351bf59a46bec7f77ffe40a68a5993","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#40-56","gmt_create":"2026-05-23T15:19:23.690208+08:00","gmt_modified":"2026-05-23T15:19:23.690208+08:00"},{"id":2108,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"cc64cf609f5ff218f618e0664ffa7cc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#298-308","gmt_create":"2026-05-23T15:19:23.691133+08:00","gmt_modified":"2026-05-23T15:19:23.691133+08:00"},{"id":2109,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"ce7e334595a4ce912e0d116314db9a35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#342-429","gmt_create":"2026-05-23T15:19:23.693626+08:00","gmt_modified":"2026-05-23T15:19:23.693627+08:00"},{"id":2110,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-05-23T15:19:23.694541+08:00","gmt_modified":"2026-05-23T15:19:23.694541+08:00"},{"id":2111,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"2f46f212597e3c245b9e5dcc5dbc863d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/citation.py#7-18","gmt_create":"2026-05-23T15:19:23.694986+08:00","gmt_modified":"2026-05-23T15:19:23.694986+08:00"},{"id":2112,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"46e69841e5c5dc62faa55c9f066586d6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#74-107","gmt_create":"2026-05-23T15:19:23.696249+08:00","gmt_modified":"2026-05-23T15:19:23.696249+08:00"},{"id":2113,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"cecc8857775f7928d465b68e429493d2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#110-140","gmt_create":"2026-05-23T15:19:23.697419+08:00","gmt_modified":"2026-05-23T15:19:23.697419+08:00"},{"id":2114,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"1153d8a149a70bc79ca59a9dcba5945c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#8-55","gmt_create":"2026-05-23T15:19:23.698372+08:00","gmt_modified":"2026-05-23T15:19:23.698372+08:00"},{"id":2115,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"35dd08df9c7a562d9c7b8edf740eaf3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#33-115","gmt_create":"2026-05-23T15:19:23.699524+08:00","gmt_modified":"2026-05-23T15:19:23.699525+08:00"},{"id":2116,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"dc40f1dd3e59ee7f046019201068bea1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#14-22","gmt_create":"2026-05-23T15:19:23.713232+08:00","gmt_modified":"2026-05-23T15:19:23.713233+08:00"},{"id":2117,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-05-23T15:19:55.78259+08:00","gmt_modified":"2026-05-23T15:19:55.78259+08:00"},{"id":2118,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-05-23T15:19:55.783376+08:00","gmt_modified":"2026-05-23T15:19:55.783376+08:00"},{"id":2119,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"5e414f2ef9b69e55e00ab15f85b9291a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/Dockerfile","gmt_create":"2026-05-23T15:19:55.784159+08:00","gmt_modified":"2026-05-23T15:19:55.78416+08:00"},{"id":2120,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:19:55.784671+08:00","gmt_modified":"2026-05-23T15:19:55.784672+08:00"},{"id":2121,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:19:55.785266+08:00","gmt_modified":"2026-05-23T15:19:55.785266+08:00"},{"id":2122,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-05-23T15:19:55.785962+08:00","gmt_modified":"2026-05-23T15:19:55.785962+08:00"},{"id":2123,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-05-23T15:19:55.823839+08:00","gmt_modified":"2026-05-23T15:19:55.82384+08:00"},{"id":2124,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-05-23T15:19:55.825129+08:00","gmt_modified":"2026-05-23T15:19:55.825129+08:00"},{"id":2125,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:19:55.827216+08:00","gmt_modified":"2026-05-23T15:19:55.827216+08:00"},{"id":2126,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-05-23T15:19:55.828339+08:00","gmt_modified":"2026-05-23T15:19:55.828339+08:00"},{"id":2127,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:19:55.829074+08:00","gmt_modified":"2026-05-23T15:19:55.829075+08:00"},{"id":2128,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic.ini","gmt_create":"2026-05-23T15:19:55.829568+08:00","gmt_modified":"2026-05-23T15:19:55.829569+08:00"},{"id":2129,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"a680d4819f5da57fe9fa0e6bc708f380","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/env.py","gmt_create":"2026-05-23T15:19:55.830029+08:00","gmt_modified":"2026-05-23T15:19:55.830029+08:00"},{"id":2130,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"b44632a0f399b2fe2b4daf295a120ec7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/logging_middleware.py","gmt_create":"2026-05-23T15:19:55.830487+08:00","gmt_modified":"2026-05-23T15:19:55.830488+08:00"},{"id":2131,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"5883a8ef4fc156d76b71ffdb5ecdf232","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/rate_limit.py","gmt_create":"2026-05-23T15:19:55.830935+08:00","gmt_modified":"2026-05-23T15:19:55.830936+08:00"},{"id":2132,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"389d631bc6c7111ba411b0b79fca455e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: tests/test_auth.py","gmt_create":"2026-05-23T15:19:55.831468+08:00","gmt_modified":"2026-05-23T15:19:55.831468+08:00"},{"id":2133,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"48d22eaee09e364a293ad6c4750f5c5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#1-71","gmt_create":"2026-05-23T15:19:55.832153+08:00","gmt_modified":"2026-05-23T15:19:55.832153+08:00"},{"id":2134,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"412695e5de2014514a8f62f98c573656","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/Dockerfile#1-41","gmt_create":"2026-05-23T15:19:55.833115+08:00","gmt_modified":"2026-05-23T15:19:55.833116+08:00"},{"id":2135,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"01a0c4b40819965823b56e9da858c024","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/Dockerfile#1-15","gmt_create":"2026-05-23T15:19:55.833968+08:00","gmt_modified":"2026-05-23T15:19:55.833968+08:00"},{"id":2136,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"cb292fb9d8227e14f98eed613b793a74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-100","gmt_create":"2026-05-23T15:19:55.834812+08:00","gmt_modified":"2026-05-23T15:19:55.834812+08:00"},{"id":2137,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"cb292fb9d8227e14f98eed613b793a74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-100","gmt_create":"2026-05-23T15:19:55.835384+08:00","gmt_modified":"2026-05-23T15:19:55.835384+08:00"},{"id":2138,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"dd36901ce62b8cc1d66667dcdc45e637","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-46","gmt_create":"2026-05-23T15:19:55.836049+08:00","gmt_modified":"2026-05-23T15:19:55.836049+08:00"},{"id":2139,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-05-23T15:19:55.837204+08:00","gmt_modified":"2026-05-23T15:19:55.837205+08:00"},{"id":2140,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"1aa2eb624a63acddcd9638630606b2e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-189","gmt_create":"2026-05-23T15:19:55.838143+08:00","gmt_modified":"2026-05-23T15:19:55.838143+08:00"},{"id":2141,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"1aa2eb624a63acddcd9638630606b2e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-189","gmt_create":"2026-05-23T15:19:55.838668+08:00","gmt_modified":"2026-05-23T15:19:55.838668+08:00"},{"id":2142,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"13f6ca76349ef86ae756bb519f122bc5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#1-150","gmt_create":"2026-05-23T15:19:55.839524+08:00","gmt_modified":"2026-05-23T15:19:55.839524+08:00"},{"id":2143,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"211463f5b49610f09594c40c0a235943","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#1-89","gmt_create":"2026-05-23T15:19:55.840322+08:00","gmt_modified":"2026-05-23T15:19:55.840322+08:00"},{"id":2144,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"a03d722c5d84b49db41742b78679a2f8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: docker-compose.yml#36-66","gmt_create":"2026-05-23T15:19:55.848078+08:00","gmt_modified":"2026-05-23T15:19:55.848078+08:00"},{"id":2145,"source_id":"fc6242433ae9506bcc0bf4cb0dce1413","target_id":"a03d722c5d84b49db41742b78679a2f8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-66","gmt_create":"2026-05-23T15:19:55.848739+08:00","gmt_modified":"2026-05-23T15:19:55.848739+08:00"},{"id":2146,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"f7e662afe370f458b73886fe90709a23","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#97-100","gmt_create":"2026-05-23T15:19:55.849586+08:00","gmt_modified":"2026-05-23T15:19:55.849586+08:00"},{"id":2147,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"f7e662afe370f458b73886fe90709a23","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 97-100","gmt_create":"2026-05-23T15:19:55.850238+08:00","gmt_modified":"2026-05-23T15:19:55.850238+08:00"},{"id":2148,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"50925c15ef4105b22c55cd16d44103a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#33-45","gmt_create":"2026-05-23T15:19:55.851594+08:00","gmt_modified":"2026-05-23T15:19:55.851594+08:00"},{"id":2149,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"50925c15ef4105b22c55cd16d44103a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-45","gmt_create":"2026-05-23T15:19:55.852082+08:00","gmt_modified":"2026-05-23T15:19:55.852083+08:00"},{"id":2150,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"6d4024210922cde4cb5f7944996640c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#12-14","gmt_create":"2026-05-23T15:19:55.852831+08:00","gmt_modified":"2026-05-23T15:19:55.852832+08:00"},{"id":2151,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"6d4024210922cde4cb5f7944996640c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-14","gmt_create":"2026-05-23T15:19:55.853566+08:00","gmt_modified":"2026-05-23T15:19:55.853566+08:00"},{"id":2152,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"b32f57d9055ac4c655dfc976b1fd51a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#33-51","gmt_create":"2026-05-23T15:19:55.855342+08:00","gmt_modified":"2026-05-23T15:19:55.855342+08:00"},{"id":2153,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"b32f57d9055ac4c655dfc976b1fd51a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-51","gmt_create":"2026-05-23T15:19:55.855957+08:00","gmt_modified":"2026-05-23T15:19:55.855957+08:00"},{"id":2154,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"6171fd1748ad5189394ba670000e7e75","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-45","gmt_create":"2026-05-23T15:19:55.864842+08:00","gmt_modified":"2026-05-23T15:19:55.864842+08:00"},{"id":2155,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"60f56d5de44cd7f96dbf71d74290910d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#53-63","gmt_create":"2026-05-23T15:19:55.865757+08:00","gmt_modified":"2026-05-23T15:19:55.865758+08:00"},{"id":2156,"source_id":"9228ff67d4c757a85d9421b71f4b29f5","target_id":"60f56d5de44cd7f96dbf71d74290910d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-63","gmt_create":"2026-05-23T15:19:55.866492+08:00","gmt_modified":"2026-05-23T15:19:55.866493+08:00"},{"id":2157,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-05-23T15:19:55.867761+08:00","gmt_modified":"2026-05-23T15:19:55.867762+08:00"},{"id":2158,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"0d92cb154d0e27b75793e9a25e3211c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#86-89","gmt_create":"2026-05-23T15:19:55.869696+08:00","gmt_modified":"2026-05-23T15:19:55.869696+08:00"},{"id":2159,"source_id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","target_id":"0d92cb154d0e27b75793e9a25e3211c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-89","gmt_create":"2026-05-23T15:19:55.870233+08:00","gmt_modified":"2026-05-23T15:19:55.870233+08:00"},{"id":2160,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"5688471e2418628ac2a6409451708d06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-115","gmt_create":"2026-05-23T15:19:55.873845+08:00","gmt_modified":"2026-05-23T15:19:55.873845+08:00"},{"id":2161,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"13b13aa0fd51de34b0cfb27187df0eb0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#14","gmt_create":"2026-05-23T15:19:55.877176+08:00","gmt_modified":"2026-05-23T15:19:55.877176+08:00"},{"id":2162,"source_id":"9ff19022ef915615911280e3c49ed44b","target_id":"13b13aa0fd51de34b0cfb27187df0eb0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 14","gmt_create":"2026-05-23T15:19:55.878341+08:00","gmt_modified":"2026-05-23T15:19:55.878341+08:00"},{"id":2163,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"00502fc9ffc15147665f96f056735d74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-42","gmt_create":"2026-05-23T15:19:55.882118+08:00","gmt_modified":"2026-05-23T15:19:55.882118+08:00"},{"id":2164,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"6c080aba7d0e611bd4e7f268835b630f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/logging_middleware.py#1-24","gmt_create":"2026-05-23T15:19:55.885798+08:00","gmt_modified":"2026-05-23T15:19:55.885798+08:00"},{"id":2165,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"a7bba55ddc4dd5d215e881e8432d83ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#1-83","gmt_create":"2026-05-23T15:19:55.887374+08:00","gmt_modified":"2026-05-23T15:19:55.887374+08:00"},{"id":2166,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"ef31f4aa4fbd1b6ff76eba467b757a04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#34-69","gmt_create":"2026-05-23T15:19:55.889039+08:00","gmt_modified":"2026-05-23T15:19:55.889039+08:00"},{"id":2167,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"dfaa01739b500883c182fe0ee7b38f02","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#35-42","gmt_create":"2026-05-23T15:19:55.889934+08:00","gmt_modified":"2026-05-23T15:19:55.889934+08:00"},{"id":2168,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"dfaa01739b500883c182fe0ee7b38f02","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-42","gmt_create":"2026-05-23T15:19:55.890525+08:00","gmt_modified":"2026-05-23T15:19:55.890525+08:00"},{"id":2169,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"1a78f5574add6d07a1d7c947dba3f23d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic.ini#115-150","gmt_create":"2026-05-23T15:19:55.899548+08:00","gmt_modified":"2026-05-23T15:19:55.899548+08:00"},{"id":2170,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"ffb7b526b388c92bf932d701fee71671","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/alembic/env.py#64-89","gmt_create":"2026-05-23T15:19:55.90053+08:00","gmt_modified":"2026-05-23T15:19:55.90053+08:00"},{"id":2171,"source_id":"a680d4819f5da57fe9fa0e6bc708f380","target_id":"ffb7b526b388c92bf932d701fee71671","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 64-89","gmt_create":"2026-05-23T15:19:55.901127+08:00","gmt_modified":"2026-05-23T15:19:55.901128+08:00"},{"id":2172,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"d820e2daf2ea133a7aa17cdc475e44a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: tests/test_auth.py#1-104","gmt_create":"2026-05-23T15:19:55.902141+08:00","gmt_modified":"2026-05-23T15:19:55.902141+08:00"},{"id":2173,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-05-23T15:22:58.410448+08:00","gmt_modified":"2026-05-23T15:22:58.410448+08:00"},{"id":2174,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"955e1dfe57f0a9a8e900383eb7641ba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/next.config.mjs","gmt_create":"2026-05-23T15:22:58.416474+08:00","gmt_modified":"2026-05-23T15:22:58.416474+08:00"},{"id":2175,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"01056dad8851d3e9bd532eb4cab33792","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/tailwind.config.ts","gmt_create":"2026-05-23T15:22:58.417787+08:00","gmt_modified":"2026-05-23T15:22:58.417788+08:00"},{"id":2176,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-05-23T15:22:58.419844+08:00","gmt_modified":"2026-05-23T15:22:58.419845+08:00"},{"id":2177,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"546e01c5f73aaf5140eee922f4b9a441","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/providers.tsx","gmt_create":"2026-05-23T15:22:58.42185+08:00","gmt_modified":"2026-05-23T15:22:58.42185+08:00"},{"id":2178,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"5800a08224424ebced854d06365f6d44","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(auth","gmt_create":"2026-05-23T15:22:58.422703+08:00","gmt_modified":"2026-05-23T15:22:58.422703+08:00"},{"id":2179,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-05-23T15:22:58.423387+08:00","gmt_modified":"2026-05-23T15:22:58.423387+08:00"},{"id":2180,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"d2c1984414de6856ed5b3873c661b712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/auth.ts","gmt_create":"2026-05-23T15:22:58.424103+08:00","gmt_modified":"2026-05-23T15:22:58.424103+08:00"},{"id":2181,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/types/next-auth.d.ts","gmt_create":"2026-05-23T15:22:58.424779+08:00","gmt_modified":"2026-05-23T15:22:58.42478+08:00"},{"id":2182,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-05-23T15:22:58.426166+08:00","gmt_modified":"2026-05-23T15:22:58.426166+08:00"},{"id":2183,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"ac1acbc54c49ee1de13369f6c6827568","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/button.tsx","gmt_create":"2026-05-23T15:22:58.434863+08:00","gmt_modified":"2026-05-23T15:22:58.434864+08:00"},{"id":2184,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"eca13a610badfc5ffc6210827fb96991","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/header.tsx","gmt_create":"2026-05-23T15:22:58.435989+08:00","gmt_modified":"2026-05-23T15:22:58.435989+08:00"},{"id":2185,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"18a0651d895fba9bb4e0c0229459efdc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/layout/sidebar.tsx","gmt_create":"2026-05-23T15:22:58.437626+08:00","gmt_modified":"2026-05-23T15:22:58.437626+08:00"},{"id":2186,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"beb87ab5aad9532647e9dbd2db7ef587","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/ui/tabs.tsx","gmt_create":"2026-05-23T15:22:58.438536+08:00","gmt_modified":"2026-05-23T15:22:58.438537+08:00"},{"id":2187,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"facea1f00ec72e00f774d0839fee7131","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: /Users/Chiguyong/Code/GEO#wiki#main#wiki#zh/[app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","gmt_create":"2026-05-23T15:22:58.439449+08:00","gmt_modified":"2026-05-23T15:22:58.439449+08:00"},{"id":2188,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"9ea18740e615a926960e829e8c583175","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/playwright.config.ts","gmt_create":"2026-05-23T15:22:58.440921+08:00","gmt_modified":"2026-05-23T15:22:58.440921+08:00"},{"id":2189,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"6f639c813a6c2a20c0c05939222f7475","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/e2e/tests/dashboard-health.spec.ts","gmt_create":"2026-05-23T15:22:58.442234+08:00","gmt_modified":"2026-05-23T15:22:58.442234+08:00"},{"id":2190,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a3a308292fda7895bf49445c417df345","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/e2e/tests/login.spec.ts","gmt_create":"2026-05-23T15:22:58.443488+08:00","gmt_modified":"2026-05-23T15:22:58.443488+08:00"},{"id":2191,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"4edcf9364f826cf2a7b686447777cc07","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/e2e/pages/dashboard.page.ts","gmt_create":"2026-05-23T15:22:58.446367+08:00","gmt_modified":"2026-05-23T15:22:58.446368+08:00"},{"id":2192,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"f6784e54bb91b7daa9c76653ba1b2c75","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/e2e/pages/login.page.ts","gmt_create":"2026-05-23T15:22:58.450857+08:00","gmt_modified":"2026-05-23T15:22:58.450858+08:00"},{"id":2193,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"1fa69729b52f34bc96b687a395501734","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/business/index.ts","gmt_create":"2026-05-23T15:22:58.452085+08:00","gmt_modified":"2026-05-23T15:22:58.452086+08:00"},{"id":2194,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"ebcf5e1a8abb3ccc9196e5749461f46b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/business/agent-status-card.tsx","gmt_create":"2026-05-23T15:22:58.45352+08:00","gmt_modified":"2026-05-23T15:22:58.453521+08:00"},{"id":2195,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"0da5aaee978edabdfebab3a8e67d803f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/business/alert-card.tsx","gmt_create":"2026-05-23T15:22:58.454283+08:00","gmt_modified":"2026-05-23T15:22:58.454284+08:00"},{"id":2196,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"0130bb8ebb0800faff59f36c5625b7f7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/dashboard/index.ts","gmt_create":"2026-05-23T15:22:58.45504+08:00","gmt_modified":"2026-05-23T15:22:58.455041+08:00"},{"id":2197,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-05-23T15:22:58.456055+08:00","gmt_modified":"2026-05-23T15:22:58.456055+08:00"},{"id":2198,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"fd18328b6582e68c30b130b912891992","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/providers.tsx#1-9","gmt_create":"2026-05-23T15:22:58.457635+08:00","gmt_modified":"2026-05-23T15:22:58.457635+08:00"},{"id":2199,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"dc735ee4a0f12140bcee122a67f4a13b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/sidebar.tsx#1-63","gmt_create":"2026-05-23T15:22:58.459345+08:00","gmt_modified":"2026-05-23T15:22:58.459345+08:00"},{"id":2200,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"bd3042a8d9b602334720b0d7b4e8ab3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/tabs.tsx#1-56","gmt_create":"2026-05-23T15:22:58.464575+08:00","gmt_modified":"2026-05-23T15:22:58.464575+08:00"},{"id":2201,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"8b7ecdb77bf7d73f30b64d82972bf1f5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/tailwind.config.ts#1-121","gmt_create":"2026-05-23T15:22:58.490873+08:00","gmt_modified":"2026-05-23T15:22:58.490873+08:00"},{"id":2202,"source_id":"01056dad8851d3e9bd532eb4cab33792","target_id":"8b7ecdb77bf7d73f30b64d82972bf1f5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-121","gmt_create":"2026-05-23T15:22:58.491953+08:00","gmt_modified":"2026-05-23T15:22:58.491954+08:00"},{"id":2203,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"f990ecd63842b3ab82f5b8c8dcde2a6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/next.config.mjs#1-5","gmt_create":"2026-05-23T15:22:58.493007+08:00","gmt_modified":"2026-05-23T15:22:58.493007+08:00"},{"id":2204,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a8bbf13a4b60cc33fd76c99c6bd6b36f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/playwright.config.ts#1-39","gmt_create":"2026-05-23T15:22:58.494166+08:00","gmt_modified":"2026-05-23T15:22:58.494166+08:00"},{"id":2205,"source_id":"9ea18740e615a926960e829e8c583175","target_id":"a8bbf13a4b60cc33fd76c99c6bd6b36f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-39","gmt_create":"2026-05-23T15:22:58.496502+08:00","gmt_modified":"2026-05-23T15:22:58.496503+08:00"},{"id":2206,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"8ca9b37cfe665abc053e0258b0d036d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/business/index.ts#1-29","gmt_create":"2026-05-23T15:22:58.498251+08:00","gmt_modified":"2026-05-23T15:22:58.498251+08:00"},{"id":2207,"source_id":"1fa69729b52f34bc96b687a395501734","target_id":"8ca9b37cfe665abc053e0258b0d036d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-29","gmt_create":"2026-05-23T15:22:58.499086+08:00","gmt_modified":"2026-05-23T15:22:58.499086+08:00"},{"id":2208,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"40325db1cb621a9af027150a8c5cf8e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/auth.ts#1-73","gmt_create":"2026-05-23T15:22:58.504658+08:00","gmt_modified":"2026-05-23T15:22:58.504658+08:00"},{"id":2209,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"d5efa0fbc545b778dd913854d860c502","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/types/next-auth.d.ts#1-29","gmt_create":"2026-05-23T15:22:58.506489+08:00","gmt_modified":"2026-05-23T15:22:58.506489+08:00"},{"id":2210,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a9fb75d1fdb833a11b36bc7b298f19be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-154","gmt_create":"2026-05-23T15:22:58.507878+08:00","gmt_modified":"2026-05-23T15:22:58.507878+08:00"},{"id":2211,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"95be577a89fbeb02578e4c3718c6ec86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/ui/button.tsx#1-57","gmt_create":"2026-05-23T15:22:58.509084+08:00","gmt_modified":"2026-05-23T15:22:58.509084+08:00"},{"id":2212,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"0d903468b55bdc63cc7e25a87a89c522","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/layout/header.tsx#1-30","gmt_create":"2026-05-23T15:22:58.510622+08:00","gmt_modified":"2026-05-23T15:22:58.510622+08:00"},{"id":2213,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"76edaefb3ec9610b238b448a797795a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/e2e/tests/dashboard-health.spec.ts#1-264","gmt_create":"2026-05-23T15:22:58.525186+08:00","gmt_modified":"2026-05-23T15:22:58.525186+08:00"},{"id":2214,"source_id":"6f639c813a6c2a20c0c05939222f7475","target_id":"76edaefb3ec9610b238b448a797795a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-264","gmt_create":"2026-05-23T15:22:58.526562+08:00","gmt_modified":"2026-05-23T15:22:58.526562+08:00"},{"id":2215,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"c413ca9685496f180a8e469f24ed082f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/e2e/tests/login.spec.ts#1-126","gmt_create":"2026-05-23T15:22:58.531057+08:00","gmt_modified":"2026-05-23T15:22:58.531057+08:00"},{"id":2216,"source_id":"a3a308292fda7895bf49445c417df345","target_id":"c413ca9685496f180a8e469f24ed082f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-126","gmt_create":"2026-05-23T15:22:58.533317+08:00","gmt_modified":"2026-05-23T15:22:58.533318+08:00"},{"id":2217,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"912411178607f349a732c3e67dccf631","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/e2e/pages/login.page.ts#1-36","gmt_create":"2026-05-23T15:22:58.566683+08:00","gmt_modified":"2026-05-23T15:22:58.566683+08:00"},{"id":2218,"source_id":"f6784e54bb91b7daa9c76653ba1b2c75","target_id":"912411178607f349a732c3e67dccf631","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-36","gmt_create":"2026-05-23T15:22:58.567563+08:00","gmt_modified":"2026-05-23T15:22:58.567563+08:00"},{"id":2219,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"4f2c0f1deb411b6b716e7cd04f42a519","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/e2e/pages/dashboard.page.ts#1-74","gmt_create":"2026-05-23T15:22:58.568454+08:00","gmt_modified":"2026-05-23T15:22:58.568454+08:00"},{"id":2220,"source_id":"4edcf9364f826cf2a7b686447777cc07","target_id":"4f2c0f1deb411b6b716e7cd04f42a519","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-74","gmt_create":"2026-05-23T15:22:58.569119+08:00","gmt_modified":"2026-05-23T15:22:58.569119+08:00"},{"id":2221,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"05a55dacbbd018dc394fa656f4e06a62","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/business/agent-status-card.tsx#1-134","gmt_create":"2026-05-23T15:22:58.572525+08:00","gmt_modified":"2026-05-23T15:22:58.572525+08:00"},{"id":2222,"source_id":"ebcf5e1a8abb3ccc9196e5749461f46b","target_id":"05a55dacbbd018dc394fa656f4e06a62","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-134","gmt_create":"2026-05-23T15:22:58.573613+08:00","gmt_modified":"2026-05-23T15:22:58.573613+08:00"},{"id":2223,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"554c0874b68d357f426fe79db129ea9f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/business/alert-card.tsx#1-203","gmt_create":"2026-05-23T15:22:58.574892+08:00","gmt_modified":"2026-05-23T15:22:58.574893+08:00"},{"id":2224,"source_id":"0da5aaee978edabdfebab3a8e67d803f","target_id":"554c0874b68d357f426fe79db129ea9f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-203","gmt_create":"2026-05-23T15:22:58.576063+08:00","gmt_modified":"2026-05-23T15:22:58.576063+08:00"},{"id":2225,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"6171fd1748ad5189394ba670000e7e75","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#1-45","gmt_create":"2026-05-23T15:22:58.58128+08:00","gmt_modified":"2026-05-23T15:22:58.58128+08:00"},{"id":2226,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:23:21.604254+08:00","gmt_modified":"2026-05-23T15:23:21.604255+08:00"},{"id":2227,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:23:21.607464+08:00","gmt_modified":"2026-05-23T15:23:21.607465+08:00"},{"id":2228,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-05-23T15:23:21.609277+08:00","gmt_modified":"2026-05-23T15:23:21.609278+08:00"},{"id":2229,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:23:21.610461+08:00","gmt_modified":"2026-05-23T15:23:21.610461+08:00"},{"id":2230,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-05-23T15:23:21.612527+08:00","gmt_modified":"2026-05-23T15:23:21.612528+08:00"},{"id":2231,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"9c224bb80474867f8ded674babaa6e11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/lifecycle.py","gmt_create":"2026-05-23T15:23:21.614986+08:00","gmt_modified":"2026-05-23T15:23:21.614986+08:00"},{"id":2232,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"63953ee6b39f159a61963104ac06f283","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/knowledge.py","gmt_create":"2026-05-23T15:23:21.617203+08:00","gmt_modified":"2026-05-23T15:23:21.617204+08:00"},{"id":2233,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:23:21.619516+08:00","gmt_modified":"2026-05-23T15:23:21.619516+08:00"},{"id":2234,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-05-23T15:23:21.621439+08:00","gmt_modified":"2026-05-23T15:23:21.62144+08:00"},{"id":2235,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-05-23T15:23:21.622573+08:00","gmt_modified":"2026-05-23T15:23:21.622573+08:00"},{"id":2236,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"984d67382822ff587452a79f89e0d336","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/analytics/tracker.py","gmt_create":"2026-05-23T15:23:21.623927+08:00","gmt_modified":"2026-05-23T15:23:21.623928+08:00"},{"id":2237,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"a0c569cd2355079f9f4045a198ddcadc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/analytics/insights.py","gmt_create":"2026-05-23T15:23:21.625824+08:00","gmt_modified":"2026-05-23T15:23:21.625825+08:00"},{"id":2238,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"45c9d96513947cae445aaaf8b58b4266","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/knowledge/rag_service.py","gmt_create":"2026-05-23T15:23:21.627901+08:00","gmt_modified":"2026-05-23T15:23:21.627902+08:00"},{"id":2239,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d9f509d2a91b503397e98066751ead0c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/__init__.py","gmt_create":"2026-05-23T15:23:21.629466+08:00","gmt_modified":"2026-05-23T15:23:21.629467+08:00"},{"id":2240,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"58a2f69ec5607ac5e4ab93266534ac01","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/citation_detector.py","gmt_create":"2026-05-23T15:23:21.637054+08:00","gmt_modified":"2026-05-23T15:23:21.637054+08:00"},{"id":2241,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"13b8f594e7cace5c8a9255dc801dcad8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/content_generator_agent.py","gmt_create":"2026-05-23T15:23:21.63889+08:00","gmt_modified":"2026-05-23T15:23:21.63889+08:00"},{"id":2242,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"750f8d79d83ee910e9d18e8a4fe37e22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/deai_agent.py","gmt_create":"2026-05-23T15:23:21.640265+08:00","gmt_modified":"2026-05-23T15:23:21.640265+08:00"},{"id":2243,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"7f8c6e94ead45ad9bab8cea9a7be2123","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/geo_optimizer_agent.py","gmt_create":"2026-05-23T15:23:21.642401+08:00","gmt_modified":"2026-05-23T15:23:21.642401+08:00"},{"id":2244,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"609a02c9e1ccc0311885a70578b86386","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/engine.py","gmt_create":"2026-05-23T15:23:21.643826+08:00","gmt_modified":"2026-05-23T15:23:21.643826+08:00"},{"id":2245,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"43642bd7bedabd97ff2f0a902b783e4e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/loader.py","gmt_create":"2026-05-23T15:23:21.645751+08:00","gmt_modified":"2026-05-23T15:23:21.645752+08:00"},{"id":2246,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"fcde401daccbe6de50f3829f021ecf55","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/dispatcher.py","gmt_create":"2026-05-23T15:23:21.651152+08:00","gmt_modified":"2026-05-23T15:23:21.651153+08:00"},{"id":2247,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:23:21.652382+08:00","gmt_modified":"2026-05-23T15:23:21.652383+08:00"},{"id":2248,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-05-23T15:23:21.654729+08:00","gmt_modified":"2026-05-23T15:23:21.654729+08:00"},{"id":2249,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"97cfe961cb7386b4022a51706ae8f5dd","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/lifecycle.py","gmt_create":"2026-05-23T15:23:21.656617+08:00","gmt_modified":"2026-05-23T15:23:21.656618+08:00"},{"id":2250,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"4774aadaa8ace576601bdaa8d3e11f74","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/knowledge.py","gmt_create":"2026-05-23T15:23:21.658596+08:00","gmt_modified":"2026-05-23T15:23:21.658596+08:00"},{"id":2251,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"daab5d62bc9559915da6c4bd52dcec91","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","gmt_create":"2026-05-23T15:23:21.659729+08:00","gmt_modified":"2026-05-23T15:23:21.65973+08:00"},{"id":2252,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"5b011956f30d4ac51420444cca8c7f08","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/workers/scheduler.py","gmt_create":"2026-05-23T15:23:21.660713+08:00","gmt_modified":"2026-05-23T15:23:21.660713+08:00"},{"id":2253,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"4d4403d720ed0580f3ed57503b584eff","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/workers/citation_engine.py","gmt_create":"2026-05-23T15:23:21.663032+08:00","gmt_modified":"2026-05-23T15:23:21.663032+08:00"},{"id":2254,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"8aa6b45626f9eb93a3f4fbf1d3206a38","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/workers/platforms/base.py","gmt_create":"2026-05-23T15:23:21.667901+08:00","gmt_modified":"2026-05-23T15:23:21.667901+08:00"},{"id":2255,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2a1c745c7b3fb7f600596be3d979bba1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/(dashboard","gmt_create":"2026-05-23T15:23:21.669728+08:00","gmt_modified":"2026-05-23T15:23:21.669729+08:00"},{"id":2256,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d5f2266643d2011c66e86af088ec637f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/charts/trend-chart.tsx","gmt_create":"2026-05-23T15:23:21.672962+08:00","gmt_modified":"2026-05-23T15:23:21.672963+08:00"},{"id":2257,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"21ab29cd896c5703dfa3461a055c0f54","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api/lifecycle.ts","gmt_create":"2026-05-23T15:23:21.673897+08:00","gmt_modified":"2026-05-23T15:23:21.673898+08:00"},{"id":2258,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-05-23T15:23:21.675204+08:00","gmt_modified":"2026-05-23T15:23:21.675205+08:00"},{"id":2259,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-05-23T15:23:21.67705+08:00","gmt_modified":"2026-05-23T15:23:21.67705+08:00"},{"id":2260,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-05-23T15:23:21.681965+08:00","gmt_modified":"2026-05-23T15:23:21.681965+08:00"},{"id":2261,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-05-23T15:23:21.68563+08:00","gmt_modified":"2026-05-23T15:23:21.68563+08:00"},{"id":2262,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d592b986bbd1c67a5932c77ea0341bed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#1-47","gmt_create":"2026-05-23T15:23:21.688324+08:00","gmt_modified":"2026-05-23T15:23:21.688324+08:00"},{"id":2263,"source_id":"58901c94d975d87e652a4dc6c8dda656","target_id":"d592b986bbd1c67a5932c77ea0341bed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-47","gmt_create":"2026-05-23T15:23:21.688921+08:00","gmt_modified":"2026-05-23T15:23:21.688921+08:00"},{"id":2264,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d2a5fdb4be830adefb3b04de2c90f204","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#1-297","gmt_create":"2026-05-23T15:23:21.69046+08:00","gmt_modified":"2026-05-23T15:23:21.690461+08:00"},{"id":2265,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"d2a5fdb4be830adefb3b04de2c90f204","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-297","gmt_create":"2026-05-23T15:23:21.691541+08:00","gmt_modified":"2026-05-23T15:23:21.691541+08:00"},{"id":2266,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"23914bed50c54bb11234aa5819aec0df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#1-502","gmt_create":"2026-05-23T15:23:21.69317+08:00","gmt_modified":"2026-05-23T15:23:21.69317+08:00"},{"id":2267,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"23914bed50c54bb11234aa5819aec0df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-502","gmt_create":"2026-05-23T15:23:21.694345+08:00","gmt_modified":"2026-05-23T15:23:21.694345+08:00"},{"id":2268,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-69","gmt_create":"2026-05-23T15:23:21.698547+08:00","gmt_modified":"2026-05-23T15:23:21.698547+08:00"},{"id":2269,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"916551131bd9ac8c9f9c8bb762af1fa4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#1-130","gmt_create":"2026-05-23T15:23:21.701218+08:00","gmt_modified":"2026-05-23T15:23:21.701218+08:00"},{"id":2270,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"7c0831c17e8c65eaed9511e17ed2a2ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#1-269","gmt_create":"2026-05-23T15:23:21.703222+08:00","gmt_modified":"2026-05-23T15:23:21.703222+08:00"},{"id":2271,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2014cd6665b187d6dccb007539278ae7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/analytics/tracker.py#1-230","gmt_create":"2026-05-23T15:23:21.706953+08:00","gmt_modified":"2026-05-23T15:23:21.706953+08:00"},{"id":2272,"source_id":"984d67382822ff587452a79f89e0d336","target_id":"2014cd6665b187d6dccb007539278ae7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-230","gmt_create":"2026-05-23T15:23:21.708307+08:00","gmt_modified":"2026-05-23T15:23:21.708307+08:00"},{"id":2273,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"451a0398486fbfcc669dc4e50c9ad6e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/analytics/insights.py#1-313","gmt_create":"2026-05-23T15:23:21.709291+08:00","gmt_modified":"2026-05-23T15:23:21.709291+08:00"},{"id":2274,"source_id":"a0c569cd2355079f9f4045a198ddcadc","target_id":"451a0398486fbfcc669dc4e50c9ad6e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-313","gmt_create":"2026-05-23T15:23:21.710004+08:00","gmt_modified":"2026-05-23T15:23:21.710004+08:00"},{"id":2275,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"897891ede0baa5b92d1b9f030a781753","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/knowledge/rag_service.py#1-43","gmt_create":"2026-05-23T15:23:21.711734+08:00","gmt_modified":"2026-05-23T15:23:21.711734+08:00"},{"id":2276,"source_id":"45c9d96513947cae445aaaf8b58b4266","target_id":"897891ede0baa5b92d1b9f030a781753","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-05-23T15:23:21.712955+08:00","gmt_modified":"2026-05-23T15:23:21.712955+08:00"},{"id":2277,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"ba54afe1867c2fa2046f8f62ad1caf3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/__init__.py#1-14","gmt_create":"2026-05-23T15:23:21.715215+08:00","gmt_modified":"2026-05-23T15:23:21.715215+08:00"},{"id":2278,"source_id":"d9f509d2a91b503397e98066751ead0c","target_id":"ba54afe1867c2fa2046f8f62ad1caf3c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-14","gmt_create":"2026-05-23T15:23:21.716251+08:00","gmt_modified":"2026-05-23T15:23:21.716251+08:00"},{"id":2279,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"74bf1d1b17dff651c44a2f4dc12d7bc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#1-536","gmt_create":"2026-05-23T15:23:21.718018+08:00","gmt_modified":"2026-05-23T15:23:21.718019+08:00"},{"id":2280,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"5dd1642d800053635d9827e12e6ea120","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#1-367","gmt_create":"2026-05-23T15:23:21.72001+08:00","gmt_modified":"2026-05-23T15:23:21.72001+08:00"},{"id":2281,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"5dd1642d800053635d9827e12e6ea120","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-367","gmt_create":"2026-05-23T15:23:21.721447+08:00","gmt_modified":"2026-05-23T15:23:21.721448+08:00"},{"id":2282,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-05-23T15:23:21.725223+08:00","gmt_modified":"2026-05-23T15:23:21.725224+08:00"},{"id":2283,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-05-23T15:23:21.728082+08:00","gmt_modified":"2026-05-23T15:23:21.728082+08:00"},{"id":2284,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"fa6144407f88a3c04dfcbac3b39bf8b1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/lifecycle.py#1-91","gmt_create":"2026-05-23T15:23:21.733468+08:00","gmt_modified":"2026-05-23T15:23:21.733468+08:00"},{"id":2285,"source_id":"97cfe961cb7386b4022a51706ae8f5dd","target_id":"fa6144407f88a3c04dfcbac3b39bf8b1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-91","gmt_create":"2026-05-23T15:23:21.734434+08:00","gmt_modified":"2026-05-23T15:23:21.734434+08:00"},{"id":2286,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"78d92049eebb9a8ceb231e7d2308aa78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/knowledge.py#1-43","gmt_create":"2026-05-23T15:23:21.736023+08:00","gmt_modified":"2026-05-23T15:23:21.736023+08:00"},{"id":2287,"source_id":"4774aadaa8ace576601bdaa8d3e11f74","target_id":"78d92049eebb9a8ceb231e7d2308aa78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-05-23T15:23:21.736893+08:00","gmt_modified":"2026-05-23T15:23:21.736893+08:00"},{"id":2288,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"9aac0f12a7ab3ebafd07a8bc408dbdcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/workers/scheduler.py#1-95","gmt_create":"2026-05-23T15:23:21.738508+08:00","gmt_modified":"2026-05-23T15:23:21.738508+08:00"},{"id":2289,"source_id":"5b011956f30d4ac51420444cca8c7f08","target_id":"9aac0f12a7ab3ebafd07a8bc408dbdcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-95","gmt_create":"2026-05-23T15:23:21.739615+08:00","gmt_modified":"2026-05-23T15:23:21.739615+08:00"},{"id":2290,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"00a305280b8ae4fb67df733a6d4c0c89","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/workers/citation_engine.py#1-309","gmt_create":"2026-05-23T15:23:21.741089+08:00","gmt_modified":"2026-05-23T15:23:21.74109+08:00"},{"id":2291,"source_id":"4d4403d720ed0580f3ed57503b584eff","target_id":"00a305280b8ae4fb67df733a6d4c0c89","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-309","gmt_create":"2026-05-23T15:23:21.742661+08:00","gmt_modified":"2026-05-23T15:23:21.742661+08:00"},{"id":2292,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"b7796fc6197ecce5beb461b9466e54a0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/trend-chart.tsx#1-60","gmt_create":"2026-05-23T15:23:21.752339+08:00","gmt_modified":"2026-05-23T15:23:21.752339+08:00"},{"id":2293,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-05-23T15:23:21.761339+08:00","gmt_modified":"2026-05-23T15:23:21.76134+08:00"},{"id":2294,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-05-23T15:23:21.766909+08:00","gmt_modified":"2026-05-23T15:23:21.76691+08:00"},{"id":2295,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-05-23T15:23:21.768831+08:00","gmt_modified":"2026-05-23T15:23:21.768831+08:00"},{"id":2296,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-05-23T15:23:21.771021+08:00","gmt_modified":"2026-05-23T15:23:21.771021+08:00"},{"id":2297,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"03a65cdcfc173217d12ad8a417f8f033","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-21","gmt_create":"2026-05-23T15:23:21.788068+08:00","gmt_modified":"2026-05-23T15:23:21.788068+08:00"},{"id":2298,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"212d822d207a4c0bd7825bbf20e188e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#59-77","gmt_create":"2026-05-23T15:23:21.80864+08:00","gmt_modified":"2026-05-23T15:23:21.808641+08:00"},{"id":2299,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"68338b3901163c41ed55d1ce10ea219a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/workers/scheduler.py#51-84","gmt_create":"2026-05-23T15:23:21.810776+08:00","gmt_modified":"2026-05-23T15:23:21.810776+08:00"},{"id":2300,"source_id":"5b011956f30d4ac51420444cca8c7f08","target_id":"68338b3901163c41ed55d1ce10ea219a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-84","gmt_create":"2026-05-23T15:23:21.812508+08:00","gmt_modified":"2026-05-23T15:23:21.812509+08:00"},{"id":2301,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"0bc629b80b2505420d45840e98a2b92d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/workers/citation_engine.py#159-234","gmt_create":"2026-05-23T15:23:21.81509+08:00","gmt_modified":"2026-05-23T15:23:21.815091+08:00"},{"id":2302,"source_id":"4d4403d720ed0580f3ed57503b584eff","target_id":"0bc629b80b2505420d45840e98a2b92d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 159-234","gmt_create":"2026-05-23T15:23:21.816686+08:00","gmt_modified":"2026-05-23T15:23:21.816686+08:00"},{"id":2303,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"4ded871d02b8119cdd985de8b220b084","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#204-234","gmt_create":"2026-05-23T15:23:21.819308+08:00","gmt_modified":"2026-05-23T15:23:21.819309+08:00"},{"id":2304,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f90f382f226eeca8bb1c111d10941fa0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#54-117","gmt_create":"2026-05-23T15:23:21.822083+08:00","gmt_modified":"2026-05-23T15:23:21.822084+08:00"},{"id":2305,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"f90f382f226eeca8bb1c111d10941fa0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 54-117","gmt_create":"2026-05-23T15:23:21.823036+08:00","gmt_modified":"2026-05-23T15:23:21.823036+08:00"},{"id":2306,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"8ece81c4077ec3e9c702e5e1092119a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#51-176","gmt_create":"2026-05-23T15:23:21.82507+08:00","gmt_modified":"2026-05-23T15:23:21.825071+08:00"},{"id":2307,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"8ece81c4077ec3e9c702e5e1092119a2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 51-176","gmt_create":"2026-05-23T15:23:21.826138+08:00","gmt_modified":"2026-05-23T15:23:21.826138+08:00"},{"id":2308,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"9552bd8a528207f18e4f3a1696f26a55","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#13-37","gmt_create":"2026-05-23T15:23:21.827167+08:00","gmt_modified":"2026-05-23T15:23:21.827167+08:00"},{"id":2309,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"753a437d837246ead62b0e16c6331284","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-69","gmt_create":"2026-05-23T15:23:21.828241+08:00","gmt_modified":"2026-05-23T15:23:21.828242+08:00"},{"id":2310,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"9b10dac7dbbb1327afc8a525bf4bd0c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/query.py#45-81","gmt_create":"2026-05-23T15:23:21.833657+08:00","gmt_modified":"2026-05-23T15:23:21.833658+08:00"},{"id":2311,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"168f54bd5cbe07c656ec3905e567862c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#291-300","gmt_create":"2026-05-23T15:23:21.837553+08:00","gmt_modified":"2026-05-23T15:23:21.837553+08:00"},{"id":2312,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"168f54bd5cbe07c656ec3905e567862c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 291-300","gmt_create":"2026-05-23T15:23:21.839019+08:00","gmt_modified":"2026-05-23T15:23:21.83902+08:00"},{"id":2313,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"b624be78e3bffd876e403cff2557b088","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#19-120","gmt_create":"2026-05-23T15:23:21.847363+08:00","gmt_modified":"2026-05-23T15:23:21.847363+08:00"},{"id":2314,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"5c67e2f70283956b2d29a3c1443eb514","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#122-146","gmt_create":"2026-05-23T15:23:21.848539+08:00","gmt_modified":"2026-05-23T15:23:21.84854+08:00"},{"id":2315,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-05-23T15:23:21.851603+08:00","gmt_modified":"2026-05-23T15:23:21.851603+08:00"},{"id":2316,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d3e817d678735f63b277894d26626924","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#10-17","gmt_create":"2026-05-23T15:23:21.853387+08:00","gmt_modified":"2026-05-23T15:23:21.853387+08:00"},{"id":2317,"source_id":"a16cf42e9559523c4f96ca4c79f9488d","target_id":"d3e817d678735f63b277894d26626924","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 10-17","gmt_create":"2026-05-23T15:23:21.854596+08:00","gmt_modified":"2026-05-23T15:23:21.854597+08:00"},{"id":2318,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f0421deca067a246711e95817e1f1b1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#151-157","gmt_create":"2026-05-23T15:23:21.859784+08:00","gmt_modified":"2026-05-23T15:23:21.859784+08:00"},{"id":2319,"source_id":"74040de652d5e57f548bb5c4adc3e1a0","target_id":"f0421deca067a246711e95817e1f1b1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 151-157","gmt_create":"2026-05-23T15:23:21.861671+08:00","gmt_modified":"2026-05-23T15:23:21.861671+08:00"},{"id":2320,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"6a21ee5392ba55b57659d404ebf5355e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/citation_detector.py#24-218","gmt_create":"2026-05-23T15:23:21.865655+08:00","gmt_modified":"2026-05-23T15:23:21.865656+08:00"},{"id":2321,"source_id":"58a2f69ec5607ac5e4ab93266534ac01","target_id":"6a21ee5392ba55b57659d404ebf5355e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-218","gmt_create":"2026-05-23T15:23:21.866773+08:00","gmt_modified":"2026-05-23T15:23:21.866773+08:00"},{"id":2322,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"76381105cd13daa99ac6376cfdab39f0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#23-299","gmt_create":"2026-05-23T15:23:21.868274+08:00","gmt_modified":"2026-05-23T15:23:21.868274+08:00"},{"id":2323,"source_id":"13b8f594e7cace5c8a9255dc801dcad8","target_id":"76381105cd13daa99ac6376cfdab39f0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-299","gmt_create":"2026-05-23T15:23:21.869317+08:00","gmt_modified":"2026-05-23T15:23:21.869317+08:00"},{"id":2324,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"ff0389ece7f710d431371a409553989c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/deai_agent.py#21-156","gmt_create":"2026-05-23T15:23:21.870814+08:00","gmt_modified":"2026-05-23T15:23:21.870814+08:00"},{"id":2325,"source_id":"750f8d79d83ee910e9d18e8a4fe37e22","target_id":"ff0389ece7f710d431371a409553989c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-156","gmt_create":"2026-05-23T15:23:21.871975+08:00","gmt_modified":"2026-05-23T15:23:21.871975+08:00"},{"id":2326,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f30316a028f81ac1c0e2f77568ba64f5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/geo_optimizer_agent.py#23-198","gmt_create":"2026-05-23T15:23:21.873473+08:00","gmt_modified":"2026-05-23T15:23:21.873473+08:00"},{"id":2327,"source_id":"7f8c6e94ead45ad9bab8cea9a7be2123","target_id":"f30316a028f81ac1c0e2f77568ba64f5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-198","gmt_create":"2026-05-23T15:23:21.874184+08:00","gmt_modified":"2026-05-23T15:23:21.874184+08:00"},{"id":2328,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"72c6b8f0be1248c2ce6e84247e81416d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#31-536","gmt_create":"2026-05-23T15:23:21.875709+08:00","gmt_modified":"2026-05-23T15:23:21.875709+08:00"},{"id":2329,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"72c6b8f0be1248c2ce6e84247e81416d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-536","gmt_create":"2026-05-23T15:23:21.877669+08:00","gmt_modified":"2026-05-23T15:23:21.877669+08:00"},{"id":2330,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"af5a9cdc724669f93a0f9f1dd790717b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#32-367","gmt_create":"2026-05-23T15:23:21.87872+08:00","gmt_modified":"2026-05-23T15:23:21.87872+08:00"},{"id":2331,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"af5a9cdc724669f93a0f9f1dd790717b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-367","gmt_create":"2026-05-23T15:23:21.880036+08:00","gmt_modified":"2026-05-23T15:23:21.880036+08:00"},{"id":2332,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"8e264e08029549dd5af31f4238522cc1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/citation_detector.py#1-218","gmt_create":"2026-05-23T15:23:21.884933+08:00","gmt_modified":"2026-05-23T15:23:21.884933+08:00"},{"id":2333,"source_id":"58a2f69ec5607ac5e4ab93266534ac01","target_id":"8e264e08029549dd5af31f4238522cc1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-218","gmt_create":"2026-05-23T15:23:21.886083+08:00","gmt_modified":"2026-05-23T15:23:21.886113+08:00"},{"id":2334,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"461200c8ca02024dd32c214c679b9664","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#1-299","gmt_create":"2026-05-23T15:23:21.888308+08:00","gmt_modified":"2026-05-23T15:23:21.888309+08:00"},{"id":2335,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"7f44b646183e17098f8ce4d2be931d3e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/deai_agent.py#1-156","gmt_create":"2026-05-23T15:23:21.889964+08:00","gmt_modified":"2026-05-23T15:23:21.889965+08:00"},{"id":2336,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"45778eaa35d92099677ba180f1067905","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/geo_optimizer_agent.py#1-198","gmt_create":"2026-05-23T15:23:21.892479+08:00","gmt_modified":"2026-05-23T15:23:21.89248+08:00"},{"id":2337,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"98d6d7fe81309b5f48907ff2c96bd9e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#190-230","gmt_create":"2026-05-23T15:23:21.898853+08:00","gmt_modified":"2026-05-23T15:23:21.898853+08:00"},{"id":2338,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"12b7988890a9e461cbccd36564a6cc82","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/lifecycle.py#138-187","gmt_create":"2026-05-23T15:23:21.901727+08:00","gmt_modified":"2026-05-23T15:23:21.901727+08:00"},{"id":2339,"source_id":"9c224bb80474867f8ded674babaa6e11","target_id":"12b7988890a9e461cbccd36564a6cc82","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 138-187","gmt_create":"2026-05-23T15:23:21.903183+08:00","gmt_modified":"2026-05-23T15:23:21.903183+08:00"},{"id":2340,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"5c9cde497ea1c98e6fe63e808f1d8ca5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/lifecycle.py#12-91","gmt_create":"2026-05-23T15:23:21.904798+08:00","gmt_modified":"2026-05-23T15:23:21.904798+08:00"},{"id":2341,"source_id":"97cfe961cb7386b4022a51706ae8f5dd","target_id":"5c9cde497ea1c98e6fe63e808f1d8ca5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-91","gmt_create":"2026-05-23T15:23:21.905691+08:00","gmt_modified":"2026-05-23T15:23:21.905691+08:00"},{"id":2342,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"058be4ad1752d83067d65bf59f958461","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api/lifecycle.ts#53-95","gmt_create":"2026-05-23T15:23:21.90988+08:00","gmt_modified":"2026-05-23T15:23:21.909881+08:00"},{"id":2343,"source_id":"21ab29cd896c5703dfa3461a055c0f54","target_id":"058be4ad1752d83067d65bf59f958461","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-95","gmt_create":"2026-05-23T15:23:21.911073+08:00","gmt_modified":"2026-05-23T15:23:21.911073+08:00"},{"id":2344,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"c549a2efc417d5646c81a100701cf72a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/analytics/tracker.py#16-51","gmt_create":"2026-05-23T15:23:21.917374+08:00","gmt_modified":"2026-05-23T15:23:21.917374+08:00"},{"id":2345,"source_id":"984d67382822ff587452a79f89e0d336","target_id":"c549a2efc417d5646c81a100701cf72a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-51","gmt_create":"2026-05-23T15:23:21.918843+08:00","gmt_modified":"2026-05-23T15:23:21.918843+08:00"},{"id":2346,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"33c1014641412422e2687463885aef5f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/analytics/insights.py#40-103","gmt_create":"2026-05-23T15:23:21.920605+08:00","gmt_modified":"2026-05-23T15:23:21.920605+08:00"},{"id":2347,"source_id":"a0c569cd2355079f9f4045a198ddcadc","target_id":"33c1014641412422e2687463885aef5f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-103","gmt_create":"2026-05-23T15:23:21.921664+08:00","gmt_modified":"2026-05-23T15:23:21.921664+08:00"},{"id":2348,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"befab5441502d9e867d85550072130fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/analytics/tracker.py#53-128","gmt_create":"2026-05-23T15:23:21.922803+08:00","gmt_modified":"2026-05-23T15:23:21.922804+08:00"},{"id":2349,"source_id":"984d67382822ff587452a79f89e0d336","target_id":"befab5441502d9e867d85550072130fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-128","gmt_create":"2026-05-23T15:23:21.924282+08:00","gmt_modified":"2026-05-23T15:23:21.924282+08:00"},{"id":2350,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"1d1a90f9679ff5937c688d465591a0ab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#217-293","gmt_create":"2026-05-23T15:23:21.92941+08:00","gmt_modified":"2026-05-23T15:23:21.929411+08:00"},{"id":2351,"source_id":"63953ee6b39f159a61963104ac06f283","target_id":"1d1a90f9679ff5937c688d465591a0ab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 217-293","gmt_create":"2026-05-23T15:23:21.931252+08:00","gmt_modified":"2026-05-23T15:23:21.931252+08:00"},{"id":2352,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f38b21f300a72d77625c203e8d9e5916","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/knowledge.py#424-501","gmt_create":"2026-05-23T15:23:21.933587+08:00","gmt_modified":"2026-05-23T15:23:21.933588+08:00"},{"id":2353,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"7f9b9025f56d8baba8136ab1b8ed49b3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/knowledge/rag_service.py#33-43","gmt_create":"2026-05-23T15:23:21.935311+08:00","gmt_modified":"2026-05-23T15:23:21.935311+08:00"},{"id":2354,"source_id":"45c9d96513947cae445aaaf8b58b4266","target_id":"7f9b9025f56d8baba8136ab1b8ed49b3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-43","gmt_create":"2026-05-23T15:23:21.936548+08:00","gmt_modified":"2026-05-23T15:23:21.936549+08:00"},{"id":2355,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"16f20ee7078a57c6910a20d49deb646f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/charts/trend-chart.tsx#22-59","gmt_create":"2026-05-23T15:23:21.941432+08:00","gmt_modified":"2026-05-23T15:23:21.941432+08:00"},{"id":2356,"source_id":"d5f2266643d2011c66e86af088ec637f","target_id":"16f20ee7078a57c6910a20d49deb646f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-59","gmt_create":"2026-05-23T15:23:21.942627+08:00","gmt_modified":"2026-05-23T15:23:21.942628+08:00"},{"id":2357,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"f457c5ae12bb63dcd5d83e4ede8efb15","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#49-56","gmt_create":"2026-05-23T15:23:21.944425+08:00","gmt_modified":"2026-05-23T15:23:21.944425+08:00"},{"id":2358,"source_id":"7538ffe4902ab6041adb28b19844962a","target_id":"f457c5ae12bb63dcd5d83e4ede8efb15","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-56","gmt_create":"2026-05-23T15:23:21.94554+08:00","gmt_modified":"2026-05-23T15:23:21.945541+08:00"},{"id":2359,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"cb57298d603df7c5572310807b629516","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#76-201","gmt_create":"2026-05-23T15:23:21.94905+08:00","gmt_modified":"2026-05-23T15:23:21.94905+08:00"},{"id":2360,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"cb57298d603df7c5572310807b629516","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 76-201","gmt_create":"2026-05-23T15:23:21.950572+08:00","gmt_modified":"2026-05-23T15:23:21.950572+08:00"},{"id":2361,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"177c73dc4e71186d9eaa1157fc0fe97f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#16-46","gmt_create":"2026-05-23T15:23:21.957479+08:00","gmt_modified":"2026-05-23T15:23:21.957479+08:00"},{"id":2362,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"84d5ec753cc381b480dfd2cc2f4228a0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/citation.py#237-268","gmt_create":"2026-05-23T15:23:21.959295+08:00","gmt_modified":"2026-05-23T15:23:21.959295+08:00"},{"id":2363,"source_id":"04e3926c080e795713bff683e7dc9d3e","target_id":"84d5ec753cc381b480dfd2cc2f4228a0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 237-268","gmt_create":"2026-05-23T15:23:21.960008+08:00","gmt_modified":"2026-05-23T15:23:21.960008+08:00"},{"id":2364,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-05-23T15:23:21.966343+08:00","gmt_modified":"2026-05-23T15:23:21.966343+08:00"},{"id":2365,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d49ddf2ff36cff1ba6702d9fe3bd253d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#35-46","gmt_create":"2026-05-23T15:23:21.97134+08:00","gmt_modified":"2026-05-23T15:23:21.971341+08:00"},{"id":2366,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"d49ddf2ff36cff1ba6702d9fe3bd253d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-46","gmt_create":"2026-05-23T15:23:21.972595+08:00","gmt_modified":"2026-05-23T15:23:21.972596+08:00"},{"id":2367,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-05-23T15:23:21.983031+08:00","gmt_modified":"2026-05-23T15:23:21.983031+08:00"},{"id":2368,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"89c74d1f6c264e3b6b0232f7c2385cc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#30-40","gmt_create":"2026-05-23T15:23:21.984142+08:00","gmt_modified":"2026-05-23T15:23:21.984142+08:00"},{"id":2369,"source_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","target_id":"89c74d1f6c264e3b6b0232f7c2385cc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-40","gmt_create":"2026-05-23T15:23:21.985389+08:00","gmt_modified":"2026-05-23T15:23:21.98539+08:00"},{"id":2370,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d51485da00706b78a1bc7eb4290c8044","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#118-154","gmt_create":"2026-05-23T15:23:21.986846+08:00","gmt_modified":"2026-05-23T15:23:21.986846+08:00"},{"id":2371,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"d51485da00706b78a1bc7eb4290c8044","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 118-154","gmt_create":"2026-05-23T15:23:21.987898+08:00","gmt_modified":"2026-05-23T15:23:21.987899+08:00"},{"id":2372,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:24:01.88966+08:00","gmt_modified":"2026-05-23T15:24:01.88966+08:00"},{"id":2373,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:24:01.890714+08:00","gmt_modified":"2026-05-23T15:24:01.890714+08:00"},{"id":2374,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-05-23T15:24:01.891767+08:00","gmt_modified":"2026-05-23T15:24:01.891768+08:00"},{"id":2375,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:24:01.893771+08:00","gmt_modified":"2026-05-23T15:24:01.893771+08:00"},{"id":2376,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-05-23T15:24:01.895137+08:00","gmt_modified":"2026-05-23T15:24:01.895137+08:00"},{"id":2377,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:24:01.899331+08:00","gmt_modified":"2026-05-23T15:24:01.899331+08:00"},{"id":2378,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-05-23T15:24:01.901077+08:00","gmt_modified":"2026-05-23T15:24:01.901077+08:00"},{"id":2379,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f26740f2a1532b38c816663a4f665dbf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/admin.py","gmt_create":"2026-05-23T15:24:01.902215+08:00","gmt_modified":"2026-05-23T15:24:01.902215+08:00"},{"id":2380,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-05-23T15:24:01.903191+08:00","gmt_modified":"2026-05-23T15:24:01.903192+08:00"},{"id":2381,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5386144bf3c668c6fa14481c0d85a214","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/subscriptions.py","gmt_create":"2026-05-23T15:24:01.904559+08:00","gmt_modified":"2026-05-23T15:24:01.904559+08:00"},{"id":2382,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b44632a0f399b2fe2b4daf295a120ec7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/logging_middleware.py","gmt_create":"2026-05-23T15:24:01.905631+08:00","gmt_modified":"2026-05-23T15:24:01.905631+08:00"},{"id":2383,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5883a8ef4fc156d76b71ffdb5ecdf232","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/middleware/rate_limit.py","gmt_create":"2026-05-23T15:24:01.906674+08:00","gmt_modified":"2026-05-23T15:24:01.906675+08:00"},{"id":2384,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-05-23T15:24:01.907695+08:00","gmt_modified":"2026-05-23T15:24:01.907695+08:00"},{"id":2385,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5013cbe89f1c6f03533eb218400cedb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/subscription.py","gmt_create":"2026-05-23T15:24:01.908564+08:00","gmt_modified":"2026-05-23T15:24:01.908564+08:00"},{"id":2386,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-05-23T15:24:01.909612+08:00","gmt_modified":"2026-05-23T15:24:01.909613+08:00"},{"id":2387,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:24:01.910653+08:00","gmt_modified":"2026-05-23T15:24:01.910653+08:00"},{"id":2388,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b4a81ef789630d0af6a8d50859d01bf3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/citation_record.py","gmt_create":"2026-05-23T15:24:01.911648+08:00","gmt_modified":"2026-05-23T15:24:01.911648+08:00"},{"id":2389,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"bceca00463fe55d3bcafda728f97f723","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/subscription.py","gmt_create":"2026-05-23T15:24:01.91297+08:00","gmt_modified":"2026-05-23T15:24:01.912971+08:00"},{"id":2390,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"069738f21ac2da7349d22683e8c36929","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query_task.py","gmt_create":"2026-05-23T15:24:01.914556+08:00","gmt_modified":"2026-05-23T15:24:01.914556+08:00"},{"id":2391,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:24:01.916029+08:00","gmt_modified":"2026-05-23T15:24:01.916029+08:00"},{"id":2392,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3809c5ab912511e0e093ba02a4fc918f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/admin.py","gmt_create":"2026-05-23T15:24:01.917356+08:00","gmt_modified":"2026-05-23T15:24:01.917356+08:00"},{"id":2393,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b250fc6c32106a7f3e0c3ad152dfc097","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/subscription.py","gmt_create":"2026-05-23T15:24:01.918488+08:00","gmt_modified":"2026-05-23T15:24:01.918488+08:00"},{"id":2394,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-05-23T15:24:01.920149+08:00","gmt_modified":"2026-05-23T15:24:01.920149+08:00"},{"id":2395,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-05-23T15:24:01.921207+08:00","gmt_modified":"2026-05-23T15:24:01.921207+08:00"},{"id":2396,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ca1e69e3279cea977bb7f660d417b4d8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/llm_adapter.py","gmt_create":"2026-05-23T15:24:01.922119+08:00","gmt_modified":"2026-05-23T15:24:01.922119+08:00"},{"id":2397,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"249d68c4ba50c523b617a8c82e7afdae","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/base.py","gmt_create":"2026-05-23T15:24:01.923776+08:00","gmt_modified":"2026-05-23T15:24:01.923777+08:00"},{"id":2398,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"fcde401daccbe6de50f3829f021ecf55","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/dispatcher.py","gmt_create":"2026-05-23T15:24:01.926306+08:00","gmt_modified":"2026-05-23T15:24:01.926307+08:00"},{"id":2399,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5d2b9655ba99a14a3accb1878bb5681a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/registry.py","gmt_create":"2026-05-23T15:24:01.92773+08:00","gmt_modified":"2026-05-23T15:24:01.92773+08:00"},{"id":2400,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"609a02c9e1ccc0311885a70578b86386","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/engine.py","gmt_create":"2026-05-23T15:24:01.929101+08:00","gmt_modified":"2026-05-23T15:24:01.929101+08:00"},{"id":2401,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"43642bd7bedabd97ff2f0a902b783e4e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/loader.py","gmt_create":"2026-05-23T15:24:01.934695+08:00","gmt_modified":"2026-05-23T15:24:01.934695+08:00"},{"id":2402,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"022c381f121cc2a65834024ca2c9b8c1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/schema.py","gmt_create":"2026-05-23T15:24:01.937634+08:00","gmt_modified":"2026-05-23T15:24:01.937634+08:00"},{"id":2403,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3a2a43dd94c9405ea91934c43cdecced","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/protocol.py","gmt_create":"2026-05-23T15:24:01.939352+08:00","gmt_modified":"2026-05-23T15:24:01.939352+08:00"},{"id":2404,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"13b8f594e7cace5c8a9255dc801dcad8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/content_generator_agent.py","gmt_create":"2026-05-23T15:24:01.940783+08:00","gmt_modified":"2026-05-23T15:24:01.940784+08:00"},{"id":2405,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7f8c6e94ead45ad9bab8cea9a7be2123","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/agents/geo_optimizer_agent.py","gmt_create":"2026-05-23T15:24:01.943003+08:00","gmt_modified":"2026-05-23T15:24:01.943003+08:00"},{"id":2406,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"1de27749fbccdfaf785545657f58d256","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/llm/factory.py","gmt_create":"2026-05-23T15:24:01.966133+08:00","gmt_modified":"2026-05-23T15:24:01.966133+08:00"},{"id":2407,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"aa6cf63a65ebf46a29606af91112eb7b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/agent.py","gmt_create":"2026-05-23T15:24:01.969813+08:00","gmt_modified":"2026-05-23T15:24:01.969813+08:00"},{"id":2408,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"fffc152ed28771e8a42e5bb2e33650cd","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/pipelines/content_production.yaml","gmt_create":"2026-05-23T15:24:01.971665+08:00","gmt_modified":"2026-05-23T15:24:01.971665+08:00"},{"id":2409,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"856c9e5eddcb40682e653dbd1a4bfc4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/pipelines/diagnosis.yaml","gmt_create":"2026-05-23T15:24:01.972907+08:00","gmt_modified":"2026-05-23T15:24:01.972907+08:00"},{"id":2410,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-05-23T15:24:01.975078+08:00","gmt_modified":"2026-05-23T15:24:01.975078+08:00"},{"id":2411,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"84fbed7d35f7752e2117a74fcaf5f0e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-17","gmt_create":"2026-05-23T15:24:01.976777+08:00","gmt_modified":"2026-05-23T15:24:01.976777+08:00"},{"id":2412,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9bfc041fe426da2eb78353827e8d9163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#1-29","gmt_create":"2026-05-23T15:24:01.978153+08:00","gmt_modified":"2026-05-23T15:24:01.978153+08:00"},{"id":2413,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6c080aba7d0e611bd4e7f268835b630f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/logging_middleware.py#1-24","gmt_create":"2026-05-23T15:24:01.981529+08:00","gmt_modified":"2026-05-23T15:24:01.981529+08:00"},{"id":2414,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"a7bba55ddc4dd5d215e881e8432d83ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#1-83","gmt_create":"2026-05-23T15:24:01.983855+08:00","gmt_modified":"2026-05-23T15:24:01.983855+08:00"},{"id":2415,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"041b88dd888e1118b1b0be80f9ec4904","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/base.py#1-223","gmt_create":"2026-05-23T15:24:01.987813+08:00","gmt_modified":"2026-05-23T15:24:01.987813+08:00"},{"id":2416,"source_id":"249d68c4ba50c523b617a8c82e7afdae","target_id":"041b88dd888e1118b1b0be80f9ec4904","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-223","gmt_create":"2026-05-23T15:24:01.988985+08:00","gmt_modified":"2026-05-23T15:24:01.988986+08:00"},{"id":2417,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"aba7dcba1181acae0e810fe447807010","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/registry.py#1-219","gmt_create":"2026-05-23T15:24:01.990499+08:00","gmt_modified":"2026-05-23T15:24:01.990499+08:00"},{"id":2418,"source_id":"5d2b9655ba99a14a3accb1878bb5681a","target_id":"aba7dcba1181acae0e810fe447807010","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-219","gmt_create":"2026-05-23T15:24:01.992162+08:00","gmt_modified":"2026-05-23T15:24:01.992162+08:00"},{"id":2419,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"5dd1642d800053635d9827e12e6ea120","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#1-367","gmt_create":"2026-05-23T15:24:01.993803+08:00","gmt_modified":"2026-05-23T15:24:01.993803+08:00"},{"id":2420,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"74bf1d1b17dff651c44a2f4dc12d7bc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#1-536","gmt_create":"2026-05-23T15:24:01.996583+08:00","gmt_modified":"2026-05-23T15:24:01.996583+08:00"},{"id":2421,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3d0cd79c03fc72299fb184947c5d0d6c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/llm/factory.py#1-66","gmt_create":"2026-05-23T15:24:01.999333+08:00","gmt_modified":"2026-05-23T15:24:01.999334+08:00"},{"id":2422,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4a0f6c5332f954161992df9247e63a97","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/llm_adapter.py#1-281","gmt_create":"2026-05-23T15:24:02.002496+08:00","gmt_modified":"2026-05-23T15:24:02.002496+08:00"},{"id":2423,"source_id":"ca1e69e3279cea977bb7f660d417b4d8","target_id":"4a0f6c5332f954161992df9247e63a97","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-281","gmt_create":"2026-05-23T15:24:02.003816+08:00","gmt_modified":"2026-05-23T15:24:02.003816+08:00"},{"id":2424,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"d432677dc357ec0518cc70701962e6bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/pipelines/content_production.yaml#1-65","gmt_create":"2026-05-23T15:24:02.005942+08:00","gmt_modified":"2026-05-23T15:24:02.005943+08:00"},{"id":2425,"source_id":"fffc152ed28771e8a42e5bb2e33650cd","target_id":"d432677dc357ec0518cc70701962e6bd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-65","gmt_create":"2026-05-23T15:24:02.008305+08:00","gmt_modified":"2026-05-23T15:24:02.008305+08:00"},{"id":2426,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3d50a008bc36ea9fed48168c2597933d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/pipelines/diagnosis.yaml#1-30","gmt_create":"2026-05-23T15:24:02.010478+08:00","gmt_modified":"2026-05-23T15:24:02.010478+08:00"},{"id":2427,"source_id":"856c9e5eddcb40682e653dbd1a4bfc4b","target_id":"3d50a008bc36ea9fed48168c2597933d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-30","gmt_create":"2026-05-23T15:24:02.011439+08:00","gmt_modified":"2026-05-23T15:24:02.01144+08:00"},{"id":2428,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e2d4838e58acc0eee236ef586abab64e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-48","gmt_create":"2026-05-23T15:24:02.017686+08:00","gmt_modified":"2026-05-23T15:24:02.017686+08:00"},{"id":2429,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8aee7654d1f435ab53d8ddaabd269fed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/database.py#6-29","gmt_create":"2026-05-23T15:24:02.019679+08:00","gmt_modified":"2026-05-23T15:24:02.019679+08:00"},{"id":2430,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"acd9e6c32084e589d5aeb1665d918dfd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#13-43","gmt_create":"2026-05-23T15:24:02.021548+08:00","gmt_modified":"2026-05-23T15:24:02.021548+08:00"},{"id":2431,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"33ec8bca51cb9f667bf91088dd6b6a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#24-48","gmt_create":"2026-05-23T15:24:02.023714+08:00","gmt_modified":"2026-05-23T15:24:02.023715+08:00"},{"id":2432,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"712424bd3bd3d5f39b1a0a72acc9952a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#10-83","gmt_create":"2026-05-23T15:24:02.026139+08:00","gmt_modified":"2026-05-23T15:24:02.02614+08:00"},{"id":2433,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9357a0fcca02068d428f4a191d08fdcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/logging_middleware.py#8-24","gmt_create":"2026-05-23T15:24:02.03014+08:00","gmt_modified":"2026-05-23T15:24:02.030141+08:00"},{"id":2434,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"069243fafe60a85cf16a0ca40fa07180","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#16-43","gmt_create":"2026-05-23T15:24:02.03315+08:00","gmt_modified":"2026-05-23T15:24:02.03315+08:00"},{"id":2435,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8efcce12915471fe5b88fe058bcf238e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#16-69","gmt_create":"2026-05-23T15:24:02.03673+08:00","gmt_modified":"2026-05-23T15:24:02.03673+08:00"},{"id":2436,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7f81ebbdde3496054e6f43f5eef366dc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#14-188","gmt_create":"2026-05-23T15:24:02.03863+08:00","gmt_modified":"2026-05-23T15:24:02.03863+08:00"},{"id":2437,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f4d57f9a78585969a006b7451ea8ce84","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#69-155","gmt_create":"2026-05-23T15:24:02.040327+08:00","gmt_modified":"2026-05-23T15:24:02.040327+08:00"},{"id":2438,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e230904202fcf7a861c6f49b84f9f863","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#25-95","gmt_create":"2026-05-23T15:24:02.042114+08:00","gmt_modified":"2026-05-23T15:24:02.042114+08:00"},{"id":2439,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"309607c54b12a6340edc086ffb4737c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#148-309","gmt_create":"2026-05-23T15:24:02.044717+08:00","gmt_modified":"2026-05-23T15:24:02.044717+08:00"},{"id":2440,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"096856da621e23e78422a15e2bfce1f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#13-22","gmt_create":"2026-05-23T15:24:02.056222+08:00","gmt_modified":"2026-05-23T15:24:02.056223+08:00"},{"id":2441,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"129b746e71a9013ceb1b0fcc59942b39","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#86-90","gmt_create":"2026-05-23T15:24:02.057668+08:00","gmt_modified":"2026-05-23T15:24:02.057668+08:00"},{"id":2442,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"608c00e1835ad72363ef08796961faca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#4-17","gmt_create":"2026-05-23T15:24:02.061919+08:00","gmt_modified":"2026-05-23T15:24:02.061919+08:00"},{"id":2443,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"d5a1fb0bd23ce9240fbf79529ef94a45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#13-43","gmt_create":"2026-05-23T15:24:02.073361+08:00","gmt_modified":"2026-05-23T15:24:02.073361+08:00"},{"id":2444,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"753a437d837246ead62b0e16c6331284","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#37-69","gmt_create":"2026-05-23T15:24:02.07737+08:00","gmt_modified":"2026-05-23T15:24:02.07737+08:00"},{"id":2445,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-05-23T15:24:02.082052+08:00","gmt_modified":"2026-05-23T15:24:02.082052+08:00"},{"id":2446,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6f637c2b0796ec533aafb3b865c11cf0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/auth.py#1-34","gmt_create":"2026-05-23T15:24:02.084374+08:00","gmt_modified":"2026-05-23T15:24:02.084374+08:00"},{"id":2447,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"56e46969bdb790a5e8f333184b878d6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#11-41","gmt_create":"2026-05-23T15:24:02.086491+08:00","gmt_modified":"2026-05-23T15:24:02.086491+08:00"},{"id":2448,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"1a439c5fed6cfd188c646e1614d56371","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/auth.py#1-69","gmt_create":"2026-05-23T15:24:02.088247+08:00","gmt_modified":"2026-05-23T15:24:02.088248+08:00"},{"id":2449,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"76e6c0abb49fec57cac4892837a143c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/deps.py#1-43","gmt_create":"2026-05-23T15:24:02.090104+08:00","gmt_modified":"2026-05-23T15:24:02.090104+08:00"},{"id":2450,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"98c02d9bb7aa6e2b6be5f7381e64fd99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#26-39","gmt_create":"2026-05-23T15:24:02.092831+08:00","gmt_modified":"2026-05-23T15:24:02.092831+08:00"},{"id":2451,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-05-23T15:24:02.096743+08:00","gmt_modified":"2026-05-23T15:24:02.096744+08:00"},{"id":2452,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"cbd0101fa84d957bcb1baaa623c6b31c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/citations.py#1-78","gmt_create":"2026-05-23T15:24:02.099354+08:00","gmt_modified":"2026-05-23T15:24:02.099355+08:00"},{"id":2453,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ec4bf600a513dc2b014c85e141d7582d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#51-85","gmt_create":"2026-05-23T15:24:02.102067+08:00","gmt_modified":"2026-05-23T15:24:02.102067+08:00"},{"id":2454,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"160b5326537d25444c40a459a01e79c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#159-234","gmt_create":"2026-05-23T15:24:02.103972+08:00","gmt_modified":"2026-05-23T15:24:02.103973+08:00"},{"id":2455,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-05-23T15:24:02.106422+08:00","gmt_modified":"2026-05-23T15:24:02.106422+08:00"},{"id":2456,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"116584ea9162c1bc05911f39f9ef82b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#1-309","gmt_create":"2026-05-23T15:24:02.1083+08:00","gmt_modified":"2026-05-23T15:24:02.1083+08:00"},{"id":2457,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4fb8856be3a581fe8303d11b2284ca29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#11-55","gmt_create":"2026-05-23T15:24:02.111934+08:00","gmt_modified":"2026-05-23T15:24:02.111934+08:00"},{"id":2458,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"fd541971cebf8a7c167d717f5c5d1ff6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#11-42","gmt_create":"2026-05-23T15:24:02.115038+08:00","gmt_modified":"2026-05-23T15:24:02.115038+08:00"},{"id":2459,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4d323bf0aaf4078f09726dc0890e5955","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#11-37","gmt_create":"2026-05-23T15:24:02.116997+08:00","gmt_modified":"2026-05-23T15:24:02.116997+08:00"},{"id":2460,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"b84f46f058847733347974841f613688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#11-39","gmt_create":"2026-05-23T15:24:02.119131+08:00","gmt_modified":"2026-05-23T15:24:02.119131+08:00"},{"id":2461,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ebc123c07512c5d5aeb1011d228a895c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/agent.py#12-206","gmt_create":"2026-05-23T15:24:02.120709+08:00","gmt_modified":"2026-05-23T15:24:02.120709+08:00"},{"id":2462,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"136f172c732d0cc130532a4f0df475a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/user.py#1-41","gmt_create":"2026-05-23T15:24:02.122577+08:00","gmt_modified":"2026-05-23T15:24:02.122578+08:00"},{"id":2463,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-05-23T15:24:02.124444+08:00","gmt_modified":"2026-05-23T15:24:02.124444+08:00"},{"id":2464,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"943c18db69a04b3137fba4cebcfea87e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/citation_record.py#1-42","gmt_create":"2026-05-23T15:24:02.126471+08:00","gmt_modified":"2026-05-23T15:24:02.126471+08:00"},{"id":2465,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"86e37040be1aeb400fab9b529f5404c8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/subscription.py#1-37","gmt_create":"2026-05-23T15:24:02.128513+08:00","gmt_modified":"2026-05-23T15:24:02.128513+08:00"},{"id":2466,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6628e006b8e5ca16160743528b6b0506","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query_task.py#1-39","gmt_create":"2026-05-23T15:24:02.130666+08:00","gmt_modified":"2026-05-23T15:24:02.130666+08:00"},{"id":2467,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"bf0d60f20f3ea5a2f2458ba86d3f9173","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/agent.py#1-206","gmt_create":"2026-05-23T15:24:02.133058+08:00","gmt_modified":"2026-05-23T15:24:02.133058+08:00"},{"id":2468,"source_id":"aa6cf63a65ebf46a29606af91112eb7b","target_id":"bf0d60f20f3ea5a2f2458ba86d3f9173","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-206","gmt_create":"2026-05-23T15:24:02.13419+08:00","gmt_modified":"2026-05-23T15:24:02.13419+08:00"},{"id":2469,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"81d750ebce1c6f458a3499de79002778","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/base.py#52-114","gmt_create":"2026-05-23T15:24:02.135532+08:00","gmt_modified":"2026-05-23T15:24:02.135532+08:00"},{"id":2470,"source_id":"249d68c4ba50c523b617a8c82e7afdae","target_id":"81d750ebce1c6f458a3499de79002778","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 52-114","gmt_create":"2026-05-23T15:24:02.136549+08:00","gmt_modified":"2026-05-23T15:24:02.13655+08:00"},{"id":2471,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"07fd98ac292cc72700ce97168ed58d9a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/base.py#148-182","gmt_create":"2026-05-23T15:24:02.13822+08:00","gmt_modified":"2026-05-23T15:24:02.13822+08:00"},{"id":2472,"source_id":"249d68c4ba50c523b617a8c82e7afdae","target_id":"07fd98ac292cc72700ce97168ed58d9a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-182","gmt_create":"2026-05-23T15:24:02.139464+08:00","gmt_modified":"2026-05-23T15:24:02.139464+08:00"},{"id":2473,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ff27531ef3cacd097bc66aa7e982158d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/registry.py#29-80","gmt_create":"2026-05-23T15:24:02.140959+08:00","gmt_modified":"2026-05-23T15:24:02.140959+08:00"},{"id":2474,"source_id":"5d2b9655ba99a14a3accb1878bb5681a","target_id":"ff27531ef3cacd097bc66aa7e982158d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-80","gmt_create":"2026-05-23T15:24:02.142015+08:00","gmt_modified":"2026-05-23T15:24:02.142015+08:00"},{"id":2475,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"27a49e5089cfba7405dc53418c54dd37","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/registry.py#156-172","gmt_create":"2026-05-23T15:24:02.143356+08:00","gmt_modified":"2026-05-23T15:24:02.143357+08:00"},{"id":2476,"source_id":"5d2b9655ba99a14a3accb1878bb5681a","target_id":"27a49e5089cfba7405dc53418c54dd37","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 156-172","gmt_create":"2026-05-23T15:24:02.144831+08:00","gmt_modified":"2026-05-23T15:24:02.144832+08:00"},{"id":2477,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c0d940dbb4ac9ef819aad6c16edc0d60","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/registry.py#174-201","gmt_create":"2026-05-23T15:24:02.14687+08:00","gmt_modified":"2026-05-23T15:24:02.146871+08:00"},{"id":2478,"source_id":"5d2b9655ba99a14a3accb1878bb5681a","target_id":"c0d940dbb4ac9ef819aad6c16edc0d60","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 174-201","gmt_create":"2026-05-23T15:24:02.148253+08:00","gmt_modified":"2026-05-23T15:24:02.148253+08:00"},{"id":2479,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f90f382f226eeca8bb1c111d10941fa0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#54-117","gmt_create":"2026-05-23T15:24:02.150151+08:00","gmt_modified":"2026-05-23T15:24:02.150152+08:00"},{"id":2480,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7a66c4fd8249f7d534ebe9092faa1124","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#169-218","gmt_create":"2026-05-23T15:24:02.151932+08:00","gmt_modified":"2026-05-23T15:24:02.151933+08:00"},{"id":2481,"source_id":"fcde401daccbe6de50f3829f021ecf55","target_id":"7a66c4fd8249f7d534ebe9092faa1124","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 169-218","gmt_create":"2026-05-23T15:24:02.153277+08:00","gmt_modified":"2026-05-23T15:24:02.153278+08:00"},{"id":2482,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7a5c445db631fd099bd752645fe46eeb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/llm/factory.py#8-66","gmt_create":"2026-05-23T15:24:02.157921+08:00","gmt_modified":"2026-05-23T15:24:02.157921+08:00"},{"id":2483,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"962888e682bf9d3ceaa4d5bd5e75bb2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/llm/factory.py#25-50","gmt_create":"2026-05-23T15:24:02.160559+08:00","gmt_modified":"2026-05-23T15:24:02.160559+08:00"},{"id":2484,"source_id":"1de27749fbccdfaf785545657f58d256","target_id":"962888e682bf9d3ceaa4d5bd5e75bb2c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-50","gmt_create":"2026-05-23T15:24:02.161428+08:00","gmt_modified":"2026-05-23T15:24:02.161428+08:00"},{"id":2485,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ea929f7dbed5834bb5b3e24ebb32a0bc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/llm_adapter.py#71-110","gmt_create":"2026-05-23T15:24:02.162864+08:00","gmt_modified":"2026-05-23T15:24:02.162864+08:00"},{"id":2486,"source_id":"ca1e69e3279cea977bb7f660d417b4d8","target_id":"ea929f7dbed5834bb5b3e24ebb32a0bc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 71-110","gmt_create":"2026-05-23T15:24:02.164264+08:00","gmt_modified":"2026-05-23T15:24:02.164265+08:00"},{"id":2487,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ef16244eb1b5c1ab8774199c05bf0151","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/llm_adapter.py#220-270","gmt_create":"2026-05-23T15:24:02.16581+08:00","gmt_modified":"2026-05-23T15:24:02.16581+08:00"},{"id":2488,"source_id":"ca1e69e3279cea977bb7f660d417b4d8","target_id":"ef16244eb1b5c1ab8774199c05bf0151","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 220-270","gmt_create":"2026-05-23T15:24:02.166559+08:00","gmt_modified":"2026-05-23T15:24:02.166559+08:00"},{"id":2489,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"678dbba75fa1ffc2d9230f9e3ef7cc6f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#111-182","gmt_create":"2026-05-23T15:24:02.169096+08:00","gmt_modified":"2026-05-23T15:24:02.169096+08:00"},{"id":2490,"source_id":"13b8f594e7cace5c8a9255dc801dcad8","target_id":"678dbba75fa1ffc2d9230f9e3ef7cc6f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-182","gmt_create":"2026-05-23T15:24:02.169914+08:00","gmt_modified":"2026-05-23T15:24:02.169914+08:00"},{"id":2491,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"c32c02777f644d164c73710bcdd9c25c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#184-252","gmt_create":"2026-05-23T15:24:02.171318+08:00","gmt_modified":"2026-05-23T15:24:02.171318+08:00"},{"id":2492,"source_id":"13b8f594e7cace5c8a9255dc801dcad8","target_id":"c32c02777f644d164c73710bcdd9c25c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 184-252","gmt_create":"2026-05-23T15:24:02.17202+08:00","gmt_modified":"2026-05-23T15:24:02.17202+08:00"},{"id":2493,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"860a2f84ff90988124545bb7386f7e45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/geo_optimizer_agent.py#104-180","gmt_create":"2026-05-23T15:24:02.173662+08:00","gmt_modified":"2026-05-23T15:24:02.173662+08:00"},{"id":2494,"source_id":"7f8c6e94ead45ad9bab8cea9a7be2123","target_id":"860a2f84ff90988124545bb7386f7e45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 104-180","gmt_create":"2026-05-23T15:24:02.174936+08:00","gmt_modified":"2026-05-23T15:24:02.174937+08:00"},{"id":2495,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"461200c8ca02024dd32c214c679b9664","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/content_generator_agent.py#1-299","gmt_create":"2026-05-23T15:24:02.183488+08:00","gmt_modified":"2026-05-23T15:24:02.183488+08:00"},{"id":2496,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"45778eaa35d92099677ba180f1067905","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/agents/geo_optimizer_agent.py#1-198","gmt_create":"2026-05-23T15:24:02.186913+08:00","gmt_modified":"2026-05-23T15:24:02.186913+08:00"},{"id":2497,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"ccbe69d125e99e73a7907f2c94c59cc3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/pipelines/content_production.yaml#9-65","gmt_create":"2026-05-23T15:24:02.191108+08:00","gmt_modified":"2026-05-23T15:24:02.191109+08:00"},{"id":2498,"source_id":"fffc152ed28771e8a42e5bb2e33650cd","target_id":"ccbe69d125e99e73a7907f2c94c59cc3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-65","gmt_create":"2026-05-23T15:24:02.192794+08:00","gmt_modified":"2026-05-23T15:24:02.192795+08:00"},{"id":2499,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"63b5e7a6a9a5545b70747bcbcae293f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/pipelines/diagnosis.yaml#8-30","gmt_create":"2026-05-23T15:24:02.194778+08:00","gmt_modified":"2026-05-23T15:24:02.194778+08:00"},{"id":2500,"source_id":"856c9e5eddcb40682e653dbd1a4bfc4b","target_id":"63b5e7a6a9a5545b70747bcbcae293f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 8-30","gmt_create":"2026-05-23T15:24:02.196037+08:00","gmt_modified":"2026-05-23T15:24:02.196037+08:00"},{"id":2501,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8ece81c4077ec3e9c702e5e1092119a2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#51-176","gmt_create":"2026-05-23T15:24:02.199542+08:00","gmt_modified":"2026-05-23T15:24:02.199543+08:00"},{"id":2502,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"cdcf6ce33785e1c04e59e8244ca38ec8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#256-327","gmt_create":"2026-05-23T15:24:02.204302+08:00","gmt_modified":"2026-05-23T15:24:02.204302+08:00"},{"id":2503,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"cdcf6ce33785e1c04e59e8244ca38ec8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 256-327","gmt_create":"2026-05-23T15:24:02.206689+08:00","gmt_modified":"2026-05-23T15:24:02.20669+08:00"},{"id":2504,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"d8a98dd989912e358f7dbd278e1c5353","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/loader.py#1-283","gmt_create":"2026-05-23T15:24:02.209677+08:00","gmt_modified":"2026-05-23T15:24:02.209677+08:00"},{"id":2505,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8d044a978198d9cd54d1b3d8e41194c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/schema.py#1-102","gmt_create":"2026-05-23T15:24:02.212021+08:00","gmt_modified":"2026-05-23T15:24:02.212021+08:00"},{"id":2506,"source_id":"022c381f121cc2a65834024ca2c9b8c1","target_id":"8d044a978198d9cd54d1b3d8e41194c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-102","gmt_create":"2026-05-23T15:24:02.214191+08:00","gmt_modified":"2026-05-23T15:24:02.214192+08:00"},{"id":2507,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9606b8243736b4a6f5ecfe152b2ab6dd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/middleware/rate_limit.py#34-83","gmt_create":"2026-05-23T15:24:02.222101+08:00","gmt_modified":"2026-05-23T15:24:02.222101+08:00"},{"id":2508,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"05664cbd35007caa5290760cc1ef1b99","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#29-108","gmt_create":"2026-05-23T15:24:02.229058+08:00","gmt_modified":"2026-05-23T15:24:02.229058+08:00"},{"id":2509,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"7c7425c51cc43b8840cefd9764b47204","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/admin.py#1-108","gmt_create":"2026-05-23T15:24:02.234822+08:00","gmt_modified":"2026-05-23T15:24:02.234823+08:00"},{"id":2510,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"9bdd2f6103cf3cc8b3914b9d6d8812fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/admin.py#1-188","gmt_create":"2026-05-23T15:24:02.237145+08:00","gmt_modified":"2026-05-23T15:24:02.237145+08:00"},{"id":2511,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"3d85cad939ce858f9c6d153d425c19fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#25-155","gmt_create":"2026-05-23T15:24:02.239313+08:00","gmt_modified":"2026-05-23T15:24:02.239313+08:00"},{"id":2512,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"4247da3fc00a7e5f8b73775321eccf8e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/subscriptions.py#1-77","gmt_create":"2026-05-23T15:24:02.242793+08:00","gmt_modified":"2026-05-23T15:24:02.242793+08:00"},{"id":2513,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"36769bd305cd5f664fa6e28f82e4b3e7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/subscription.py#1-41","gmt_create":"2026-05-23T15:24:02.244875+08:00","gmt_modified":"2026-05-23T15:24:02.244875+08:00"},{"id":2514,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"557281ca025f76d0dc2db67e56b44053","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/services/subscription.py#1-155","gmt_create":"2026-05-23T15:24:02.25128+08:00","gmt_modified":"2026-05-23T15:24:02.25128+08:00"},{"id":2515,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"14c2d098319eeab16c64ff7d1447df6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#18-75","gmt_create":"2026-05-23T15:24:02.25351+08:00","gmt_modified":"2026-05-23T15:24:02.25351+08:00"},{"id":2516,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"6e4a52820e780e4b42651a8214ad4493","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/reports.py#1-75","gmt_create":"2026-05-23T15:24:02.255272+08:00","gmt_modified":"2026-05-23T15:24:02.255272+08:00"},{"id":2517,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"eb603ec2611957de67af00756f4b1efa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7-13","gmt_create":"2026-05-23T15:24:02.3019+08:00","gmt_modified":"2026-05-23T15:24:02.3019+08:00"},{"id":2518,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"e1d2b027678118df4d0a50ce9269271d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#42-90","gmt_create":"2026-05-23T15:24:02.306153+08:00","gmt_modified":"2026-05-23T15:24:02.306154+08:00"},{"id":2519,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"38142b7d7016c5590e638fafcdcb1a19","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/citation_engine.py#211-227","gmt_create":"2026-05-23T15:24:02.307777+08:00","gmt_modified":"2026-05-23T15:24:02.307777+08:00"},{"id":2520,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"960edc307c80a05c1d234e641a795b35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/llm_adapter.py#141-218","gmt_create":"2026-05-23T15:24:02.318511+08:00","gmt_modified":"2026-05-23T15:24:02.318511+08:00"},{"id":2521,"source_id":"ca1e69e3279cea977bb7f660d417b4d8","target_id":"960edc307c80a05c1d234e641a795b35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 141-218","gmt_create":"2026-05-23T15:24:02.324725+08:00","gmt_modified":"2026-05-23T15:24:02.324726+08:00"},{"id":2522,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"8bf01ba5b11502e9f6f9802c9735f370","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/loader.py#124-134","gmt_create":"2026-05-23T15:24:02.330086+08:00","gmt_modified":"2026-05-23T15:24:02.330086+08:00"},{"id":2523,"source_id":"43642bd7bedabd97ff2f0a902b783e4e","target_id":"8bf01ba5b11502e9f6f9802c9735f370","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 124-134","gmt_create":"2026-05-23T15:24:02.33248+08:00","gmt_modified":"2026-05-23T15:24:02.332481+08:00"},{"id":2524,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"9228ff67d4c757a85d9421b71f4b29f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/main.py","gmt_create":"2026-05-23T15:26:09.959877+08:00","gmt_modified":"2026-05-23T15:26:09.959878+08:00"},{"id":2525,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"9ff19022ef915615911280e3c49ed44b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/config.py","gmt_create":"2026-05-23T15:26:09.96188+08:00","gmt_modified":"2026-05-23T15:26:09.961881+08:00"},{"id":2526,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"93022c8938ce318f167277cfa65c29a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/auth.py","gmt_create":"2026-05-23T15:26:09.963003+08:00","gmt_modified":"2026-05-23T15:26:09.963004+08:00"},{"id":2527,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6b3d903205941aa9391dd90016e1102c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/queries.py","gmt_create":"2026-05-23T15:26:09.964609+08:00","gmt_modified":"2026-05-23T15:26:09.964609+08:00"},{"id":2528,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"58901c94d975d87e652a4dc6c8dda656","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/reports.py","gmt_create":"2026-05-23T15:26:09.966371+08:00","gmt_modified":"2026-05-23T15:26:09.966372+08:00"},{"id":2529,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"7538ffe4902ab6041adb28b19844962a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/citations.py","gmt_create":"2026-05-23T15:26:09.967943+08:00","gmt_modified":"2026-05-23T15:26:09.967944+08:00"},{"id":2530,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6a9387dd3885cf4d27bce3db87fd61c7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/agents.py","gmt_create":"2026-05-23T15:26:09.968693+08:00","gmt_modified":"2026-05-23T15:26:09.968693+08:00"},{"id":2531,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"b74caccb06844efcdb14d8324cff65c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/query.py","gmt_create":"2026-05-23T15:26:09.969487+08:00","gmt_modified":"2026-05-23T15:26:09.969487+08:00"},{"id":2532,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"f301b79d833233ce39d350e82a71c938","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/query.py","gmt_create":"2026-05-23T15:26:09.970813+08:00","gmt_modified":"2026-05-23T15:26:09.970813+08:00"},{"id":2533,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"5cbb1e3f112aeba62a14b0b8999fc0f5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/scheduler.py","gmt_create":"2026-05-23T15:26:09.972359+08:00","gmt_modified":"2026-05-23T15:26:09.972359+08:00"},{"id":2534,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"a16cf42e9559523c4f96ca4c79f9488d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/base.py","gmt_create":"2026-05-23T15:26:09.973803+08:00","gmt_modified":"2026-05-23T15:26:09.973803+08:00"},{"id":2535,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"8f973791233c698b3e64a4fb28a93d4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/kimi.py","gmt_create":"2026-05-23T15:26:09.97491+08:00","gmt_modified":"2026-05-23T15:26:09.97491+08:00"},{"id":2536,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"f642fc1c2f34e15572d9d98aa6c18813","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/platforms/wenxin.py","gmt_create":"2026-05-23T15:26:09.97652+08:00","gmt_modified":"2026-05-23T15:26:09.97652+08:00"},{"id":2537,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"74040de652d5e57f548bb5c4adc3e1a0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/workers/citation_engine.py","gmt_create":"2026-05-23T15:26:09.977692+08:00","gmt_modified":"2026-05-23T15:26:09.977692+08:00"},{"id":2538,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"4d2f3847b7c10634733118b70a1aea0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/auth.py","gmt_create":"2026-05-23T15:26:09.978675+08:00","gmt_modified":"2026-05-23T15:26:09.978675+08:00"},{"id":2539,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"88d22de3b2a7419868e8ae19130d860c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/query.py","gmt_create":"2026-05-23T15:26:09.979339+08:00","gmt_modified":"2026-05-23T15:26:09.979339+08:00"},{"id":2540,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"04e3926c080e795713bff683e7dc9d3e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/services/citation.py","gmt_create":"2026-05-23T15:26:09.980266+08:00","gmt_modified":"2026-05-23T15:26:09.980266+08:00"},{"id":2541,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"b0c428683c8a3e6922d90ca0d8c2736d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/database.py","gmt_create":"2026-05-23T15:26:09.981705+08:00","gmt_modified":"2026-05-23T15:26:09.981706+08:00"},{"id":2542,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"9d08667997a868fc07c9b4e328e44224","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/api/deps.py","gmt_create":"2026-05-23T15:26:09.984465+08:00","gmt_modified":"2026-05-23T15:26:09.984465+08:00"},{"id":2543,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"c59f8c276697a070dffc581fe94d809c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/user.py","gmt_create":"2026-05-23T15:26:09.98624+08:00","gmt_modified":"2026-05-23T15:26:09.986241+08:00"},{"id":2544,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e0c0ca66b8b81cf66e078a7ab162c07f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/auth.py","gmt_create":"2026-05-23T15:26:09.987271+08:00","gmt_modified":"2026-05-23T15:26:09.987271+08:00"},{"id":2545,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"1a3336b4af8a39a055e912724338580c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/schemas/citation.py","gmt_create":"2026-05-23T15:26:09.98798+08:00","gmt_modified":"2026-05-23T15:26:09.98798+08:00"},{"id":2546,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"a26ee01cf41da3b956e1650448c156fa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/requirements.txt","gmt_create":"2026-05-23T15:26:09.988952+08:00","gmt_modified":"2026-05-23T15:26:09.988952+08:00"},{"id":2547,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"12e2c3d7b9a92dc44a6ee29b85e10df6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/app/layout.tsx","gmt_create":"2026-05-23T15:26:09.989956+08:00","gmt_modified":"2026-05-23T15:26:09.989956+08:00"},{"id":2548,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"546e01c5f73aaf5140eee922f4b9a441","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/components/providers.tsx","gmt_create":"2026-05-23T15:26:09.991346+08:00","gmt_modified":"2026-05-23T15:26:09.991346+08:00"},{"id":2549,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"5d7886d0dc99f81073a578b8aefdd375","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api.ts","gmt_create":"2026-05-23T15:26:09.99246+08:00","gmt_modified":"2026-05-23T15:26:09.992461+08:00"},{"id":2550,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"aa21995469cad3e13897d5dbe268533f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/lib/api/agents.ts","gmt_create":"2026-05-23T15:26:09.993452+08:00","gmt_modified":"2026-05-23T15:26:09.993452+08:00"},{"id":2551,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"aaf5bce6be82d2f947bfa5c1806de452","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/package.json","gmt_create":"2026-05-23T15:26:09.99453+08:00","gmt_modified":"2026-05-23T15:26:09.994531+08:00"},{"id":2552,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"fc6242433ae9506bcc0bf4cb0dce1413","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: docker-compose.yml","gmt_create":"2026-05-23T15:26:09.997075+08:00","gmt_modified":"2026-05-23T15:26:09.997076+08:00"},{"id":2553,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e9b52adbec3c07cf021e488dd3f99ab4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/Dockerfile","gmt_create":"2026-05-23T15:26:09.998723+08:00","gmt_modified":"2026-05-23T15:26:09.998723+08:00"},{"id":2554,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"5e414f2ef9b69e55e00ab15f85b9291a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: frontend/Dockerfile","gmt_create":"2026-05-23T15:26:10.001175+08:00","gmt_modified":"2026-05-23T15:26:10.001175+08:00"},{"id":2555,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"d4f95fcf50683b5bf6167c7d2a6b126d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-05-23T15:26:10.002952+08:00","gmt_modified":"2026-05-23T15:26:10.002953+08:00"},{"id":2556,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"5d2b9655ba99a14a3accb1878bb5681a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/registry.py","gmt_create":"2026-05-23T15:26:10.005018+08:00","gmt_modified":"2026-05-23T15:26:10.005019+08:00"},{"id":2557,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6b50314c917457b8b70ade390573c3cb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/config_manager.py","gmt_create":"2026-05-23T15:26:10.00594+08:00","gmt_modified":"2026-05-23T15:26:10.00594+08:00"},{"id":2558,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"fcde401daccbe6de50f3829f021ecf55","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/dispatcher.py","gmt_create":"2026-05-23T15:26:10.007122+08:00","gmt_modified":"2026-05-23T15:26:10.007122+08:00"},{"id":2559,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"3a2a43dd94c9405ea91934c43cdecced","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/protocol.py","gmt_create":"2026-05-23T15:26:10.008461+08:00","gmt_modified":"2026-05-23T15:26:10.008461+08:00"},{"id":2560,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"609a02c9e1ccc0311885a70578b86386","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/agent_framework/pipeline/engine.py","gmt_create":"2026-05-23T15:26:10.009222+08:00","gmt_modified":"2026-05-23T15:26:10.009223+08:00"},{"id":2561,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"aa6cf63a65ebf46a29606af91112eb7b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: backend/app/models/agent.py","gmt_create":"2026-05-23T15:26:10.010633+08:00","gmt_modified":"2026-05-23T15:26:10.010633+08:00"},{"id":2562,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"c2036406c4a0ae8b1e671ef1f1601826","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: .env.example","gmt_create":"2026-05-23T15:26:10.012593+08:00","gmt_modified":"2026-05-23T15:26:10.012594+08:00"},{"id":2563,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"c2747ca16b879bca0f68955534c3c4fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#1-48","gmt_create":"2026-05-23T15:26:10.014439+08:00","gmt_modified":"2026-05-23T15:26:10.014439+08:00"},{"id":2564,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"70985e6be46865e7b0a26fdaab7ce0d2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1-58","gmt_create":"2026-05-23T15:26:10.019115+08:00","gmt_modified":"2026-05-23T15:26:10.019115+08:00"},{"id":2565,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"70985e6be46865e7b0a26fdaab7ce0d2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-58","gmt_create":"2026-05-23T15:26:10.020704+08:00","gmt_modified":"2026-05-23T15:26:10.020705+08:00"},{"id":2566,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"42315d289241195bda33f7251dff0396","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api/agents.ts#1-57","gmt_create":"2026-05-23T15:26:10.022448+08:00","gmt_modified":"2026-05-23T15:26:10.022448+08:00"},{"id":2567,"source_id":"aa21995469cad3e13897d5dbe268533f","target_id":"42315d289241195bda33f7251dff0396","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-05-23T15:26:10.023777+08:00","gmt_modified":"2026-05-23T15:26:10.023777+08:00"},{"id":2568,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"71f98c8993fb42b108e34a554247869b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#1-95","gmt_create":"2026-05-23T15:26:10.025151+08:00","gmt_modified":"2026-05-23T15:26:10.025151+08:00"},{"id":2569,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"72a110dca58d8152758e2fdab4e94761","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/base.py#1-18","gmt_create":"2026-05-23T15:26:10.026269+08:00","gmt_modified":"2026-05-23T15:26:10.026269+08:00"},{"id":2570,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"39a3b2d9301fa4eff7bef0fda3352790","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#1-206","gmt_create":"2026-05-23T15:26:10.027803+08:00","gmt_modified":"2026-05-23T15:26:10.027803+08:00"},{"id":2571,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"fbcfae3b1238b3da5329ebafe4294861","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/wenxin.py#1-205","gmt_create":"2026-05-23T15:26:10.029396+08:00","gmt_modified":"2026-05-23T15:26:10.029397+08:00"},{"id":2572,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"aba7dcba1181acae0e810fe447807010","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/registry.py#1-219","gmt_create":"2026-05-23T15:26:10.031015+08:00","gmt_modified":"2026-05-23T15:26:10.031015+08:00"},{"id":2573,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"370e7d15bc2a240ba54af22c704f8192","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/config_manager.py#1-191","gmt_create":"2026-05-23T15:26:10.034543+08:00","gmt_modified":"2026-05-23T15:26:10.034543+08:00"},{"id":2574,"source_id":"6b50314c917457b8b70ade390573c3cb","target_id":"370e7d15bc2a240ba54af22c704f8192","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-191","gmt_create":"2026-05-23T15:26:10.035987+08:00","gmt_modified":"2026-05-23T15:26:10.035987+08:00"},{"id":2575,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"5dd1642d800053635d9827e12e6ea120","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/dispatcher.py#1-367","gmt_create":"2026-05-23T15:26:10.03743+08:00","gmt_modified":"2026-05-23T15:26:10.037431+08:00"},{"id":2576,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"db3ad017a4a81f38a1e6008d01fb07fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/agent_framework/pipeline/engine.py#1-376","gmt_create":"2026-05-23T15:26:10.038939+08:00","gmt_modified":"2026-05-23T15:26:10.03894+08:00"},{"id":2577,"source_id":"609a02c9e1ccc0311885a70578b86386","target_id":"db3ad017a4a81f38a1e6008d01fb07fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-376","gmt_create":"2026-05-23T15:26:10.040091+08:00","gmt_modified":"2026-05-23T15:26:10.040092+08:00"},{"id":2578,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"8a466b0c6eac2ccb54c5da7e13854646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/app/layout.tsx#1-37","gmt_create":"2026-05-23T15:26:10.042941+08:00","gmt_modified":"2026-05-23T15:26:10.042941+08:00"},{"id":2579,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"fd18328b6582e68c30b130b912891992","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/components/providers.tsx#1-9","gmt_create":"2026-05-23T15:26:10.044621+08:00","gmt_modified":"2026-05-23T15:26:10.044622+08:00"},{"id":2580,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"f66d9907b467b110c638bd527efd95c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/auth.py#1-43","gmt_create":"2026-05-23T15:26:10.046386+08:00","gmt_modified":"2026-05-23T15:26:10.046387+08:00"},{"id":2581,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"10d1e37bdc9f353c189b7a2fe79dc85e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/queries.py#1-86","gmt_create":"2026-05-23T15:26:10.047692+08:00","gmt_modified":"2026-05-23T15:26:10.047692+08:00"},{"id":2582,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"41c1962c6c680f23f0fde4efc0edc618","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/api/agents.py#1-299","gmt_create":"2026-05-23T15:26:10.052723+08:00","gmt_modified":"2026-05-23T15:26:10.052724+08:00"},{"id":2583,"source_id":"6a9387dd3885cf4d27bce3db87fd61c7","target_id":"41c1962c6c680f23f0fde4efc0edc618","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-299","gmt_create":"2026-05-23T15:26:10.054022+08:00","gmt_modified":"2026-05-23T15:26:10.054023+08:00"},{"id":2584,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6281fff17a86ec1895c64d87c2ae7fb1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/query.py#1-55","gmt_create":"2026-05-23T15:26:10.056182+08:00","gmt_modified":"2026-05-23T15:26:10.056182+08:00"},{"id":2585,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"a0eac56d622a2fff529bc2b796064bcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#1-94","gmt_create":"2026-05-23T15:26:10.058098+08:00","gmt_modified":"2026-05-23T15:26:10.058099+08:00"},{"id":2586,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6286d4be455dc058c8be2ee4e0d1175a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#38-42","gmt_create":"2026-05-23T15:26:10.078591+08:00","gmt_modified":"2026-05-23T15:26:10.078592+08:00"},{"id":2587,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"bf0d60f20f3ea5a2f2458ba86d3f9173","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/models/agent.py#1-206","gmt_create":"2026-05-23T15:26:10.096602+08:00","gmt_modified":"2026-05-23T15:26:10.096603+08:00"},{"id":2588,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"dd36901ce62b8cc1d66667dcdc45e637","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#1-46","gmt_create":"2026-05-23T15:26:10.135722+08:00","gmt_modified":"2026-05-23T15:26:10.135722+08:00"},{"id":2589,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"08d06b8b6e8c01974ec66e0a5b10795f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#6-8","gmt_create":"2026-05-23T15:26:10.138241+08:00","gmt_modified":"2026-05-23T15:26:10.138241+08:00"},{"id":2590,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"08d06b8b6e8c01974ec66e0a5b10795f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-8","gmt_create":"2026-05-23T15:26:10.139566+08:00","gmt_modified":"2026-05-23T15:26:10.139567+08:00"},{"id":2591,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"1ee5153c867fc6e9d277a3067963a1fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/scheduler.py#32-38","gmt_create":"2026-05-23T15:26:10.145894+08:00","gmt_modified":"2026-05-23T15:26:10.145895+08:00"},{"id":2592,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"a6811a3e7a5e0874867a1839912ac150","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#1","gmt_create":"2026-05-23T15:26:10.164126+08:00","gmt_modified":"2026-05-23T15:26:10.164126+08:00"},{"id":2593,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"a6811a3e7a5e0874867a1839912ac150","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1","gmt_create":"2026-05-23T15:26:10.167766+08:00","gmt_modified":"2026-05-23T15:26:10.167771+08:00"},{"id":2594,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"7480204ff8e76e1fedc3c82967acbddf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: .env.example#1-35","gmt_create":"2026-05-23T15:26:10.175436+08:00","gmt_modified":"2026-05-23T15:26:10.175437+08:00"},{"id":2595,"source_id":"c2036406c4a0ae8b1e671ef1f1601826","target_id":"7480204ff8e76e1fedc3c82967acbddf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-35","gmt_create":"2026-05-23T15:26:10.18136+08:00","gmt_modified":"2026-05-23T15:26:10.18136+08:00"},{"id":2596,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"b41c589b6a7e0c0addb0aa1d78666cf7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/schemas/query.py#6","gmt_create":"2026-05-23T15:26:10.194836+08:00","gmt_modified":"2026-05-23T15:26:10.194836+08:00"},{"id":2597,"source_id":"f301b79d833233ce39d350e82a71c938","target_id":"b41c589b6a7e0c0addb0aa1d78666cf7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6","gmt_create":"2026-05-23T15:26:10.195771+08:00","gmt_modified":"2026-05-23T15:26:10.195771+08:00"},{"id":2598,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"d20fc729a5d3986b1c077f9e07ece9c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/config.py#7","gmt_create":"2026-05-23T15:26:10.197696+08:00","gmt_modified":"2026-05-23T15:26:10.197696+08:00"},{"id":2599,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"05089063cd933e72db9ddd32806194bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#5-8","gmt_create":"2026-05-23T15:26:10.201339+08:00","gmt_modified":"2026-05-23T15:26:10.201339+08:00"},{"id":2600,"source_id":"a26ee01cf41da3b956e1650448c156fa","target_id":"05089063cd933e72db9ddd32806194bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5-8","gmt_create":"2026-05-23T15:26:10.20309+08:00","gmt_modified":"2026-05-23T15:26:10.203091+08:00"},{"id":2601,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"0a7f1ad960e7961b21073bdd1dbef2cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#3-21","gmt_create":"2026-05-23T15:26:10.20642+08:00","gmt_modified":"2026-05-23T15:26:10.20642+08:00"},{"id":2602,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"0a7f1ad960e7961b21073bdd1dbef2cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-21","gmt_create":"2026-05-23T15:26:10.207549+08:00","gmt_modified":"2026-05-23T15:26:10.207549+08:00"},{"id":2603,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"c099b506f31f17751b7e08f64b2b1cbe","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/lib/api.ts#16-21","gmt_create":"2026-05-23T15:26:10.227241+08:00","gmt_modified":"2026-05-23T15:26:10.227242+08:00"},{"id":2604,"source_id":"5d7886d0dc99f81073a578b8aefdd375","target_id":"c099b506f31f17751b7e08f64b2b1cbe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-21","gmt_create":"2026-05-23T15:26:10.228953+08:00","gmt_modified":"2026-05-23T15:26:10.228953+08:00"},{"id":2605,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"7289a3568c137c8a671fc8c963bb8d28","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/requirements.txt#1-35","gmt_create":"2026-05-23T15:26:10.234133+08:00","gmt_modified":"2026-05-23T15:26:10.234133+08:00"},{"id":2606,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"c45dbdda70a8b9f02b52af4991644d0b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: frontend/package.json#11-27","gmt_create":"2026-05-23T15:26:10.235735+08:00","gmt_modified":"2026-05-23T15:26:10.235735+08:00"},{"id":2607,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"3365fa8db33d43bab1d0a614e8af3a70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#45-47","gmt_create":"2026-05-23T15:26:10.240933+08:00","gmt_modified":"2026-05-23T15:26:10.240933+08:00"},{"id":2608,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"9f6d9941f3b93e29d714bfec7e83434c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/main.py#30-36","gmt_create":"2026-05-23T15:26:10.243025+08:00","gmt_modified":"2026-05-23T15:26:10.243026+08:00"},{"id":2609,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"6997483bdbba1455b9454fe4cccbba45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: backend/app/workers/platforms/kimi.py#23-32","gmt_create":"2026-05-23T15:26:10.246518+08:00","gmt_modified":"2026-05-23T15:26:10.246519+08:00"},{"id":2610,"source_id":"8f973791233c698b3e64a4fb28a93d4b","target_id":"6997483bdbba1455b9454fe4cccbba45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-32","gmt_create":"2026-05-23T15:26:10.248783+08:00","gmt_modified":"2026-05-23T15:26:10.248783+08:00"},{"id":2611,"source_id":"34e572eb-6fc8-4de7-8061-63783ef8be24","target_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 34e572eb-6fc8-4de7-8061-63783ef8be24 -\u003e 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","gmt_create":"2026-05-23T15:26:11.42441+08:00","gmt_modified":"2026-05-23T15:26:11.424411+08:00"},{"id":2612,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","gmt_create":"2026-05-23T15:26:11.426597+08:00","gmt_modified":"2026-05-23T15:26:11.426597+08:00"},{"id":2613,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"df661133-efbf-43fe-97c3-f581c81f47a7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e df661133-efbf-43fe-97c3-f581c81f47a7","gmt_create":"2026-05-23T15:26:11.42852+08:00","gmt_modified":"2026-05-23T15:26:11.428521+08:00"},{"id":2614,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"11936bb5-374f-40f4-bb53-b75264fc4b9d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 11936bb5-374f-40f4-bb53-b75264fc4b9d","gmt_create":"2026-05-23T15:26:11.430157+08:00","gmt_modified":"2026-05-23T15:26:11.430158+08:00"},{"id":2615,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"23ad3419-5473-4e2c-ac87-d9715090279d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 23ad3419-5473-4e2c-ac87-d9715090279d","gmt_create":"2026-05-23T15:26:11.432268+08:00","gmt_modified":"2026-05-23T15:26:11.432268+08:00"},{"id":2616,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"19e75845-5147-4aeb-90be-16f3aa270465","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 19e75845-5147-4aeb-90be-16f3aa270465","gmt_create":"2026-05-23T15:26:11.434024+08:00","gmt_modified":"2026-05-23T15:26:11.434024+08:00"},{"id":2617,"source_id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","target_id":"83fe6837-7874-4467-8114-103062f15f58","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c7eb113b-b503-4d83-be7f-9ccf3350c9d9 -\u003e 83fe6837-7874-4467-8114-103062f15f58","gmt_create":"2026-05-23T15:26:11.435215+08:00","gmt_modified":"2026-05-23T15:26:11.435215+08:00"},{"id":2618,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","gmt_create":"2026-05-23T15:26:11.43808+08:00","gmt_modified":"2026-05-23T15:26:11.43808+08:00"},{"id":2619,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"2b32ec11-d228-42c0-9232-103ba7e44f71","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 2b32ec11-d228-42c0-9232-103ba7e44f71","gmt_create":"2026-05-23T15:26:11.440929+08:00","gmt_modified":"2026-05-23T15:26:11.440929+08:00"},{"id":2620,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e ba0390b3-c249-4e92-a3c8-6820343aeda9","gmt_create":"2026-05-23T15:26:11.442379+08:00","gmt_modified":"2026-05-23T15:26:11.442379+08:00"},{"id":2621,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"760610d4-dff6-4c6d-831f-7c9078db86a6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 760610d4-dff6-4c6d-831f-7c9078db86a6","gmt_create":"2026-05-23T15:26:11.44359+08:00","gmt_modified":"2026-05-23T15:26:11.44359+08:00"},{"id":2622,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"a40267bc-925a-4364-a01f-b96d3df60aea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e a40267bc-925a-4364-a01f-b96d3df60aea","gmt_create":"2026-05-23T15:26:11.445284+08:00","gmt_modified":"2026-05-23T15:26:11.445284+08:00"},{"id":2623,"source_id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","target_id":"7bd2c461-81b0-48e8-8cb3-b4b14305806d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3af3bb9e-4d99-4dc3-b1ed-2686db385c26 -\u003e 7bd2c461-81b0-48e8-8cb3-b4b14305806d","gmt_create":"2026-05-23T15:26:11.446751+08:00","gmt_modified":"2026-05-23T15:26:11.446752+08:00"},{"id":2624,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"d5c75004-b01b-416f-850a-4791c5489a32","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e d5c75004-b01b-416f-850a-4791c5489a32","gmt_create":"2026-05-23T15:26:11.468281+08:00","gmt_modified":"2026-05-23T15:26:11.468281+08:00"},{"id":2625,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","gmt_create":"2026-05-23T15:26:11.470185+08:00","gmt_modified":"2026-05-23T15:26:11.470185+08:00"},{"id":2626,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"262a3941-fdc6-46b0-b767-be40aa9d5761","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e 262a3941-fdc6-46b0-b767-be40aa9d5761","gmt_create":"2026-05-23T15:26:11.471306+08:00","gmt_modified":"2026-05-23T15:26:11.471306+08:00"},{"id":2627,"source_id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","target_id":"7c0201f7-9e02-4cba-9ee1-81c3477f049a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ffbb970e-56e0-40ad-bd88-1a1e55482d96 -\u003e 7c0201f7-9e02-4cba-9ee1-81c3477f049a","gmt_create":"2026-05-23T15:26:11.472613+08:00","gmt_modified":"2026-05-23T15:26:11.472613+08:00"},{"id":2628,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"7c7564ee-7fe2-4555-8ff0-4ec1b757997a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 7c7564ee-7fe2-4555-8ff0-4ec1b757997a","gmt_create":"2026-05-23T15:26:11.478176+08:00","gmt_modified":"2026-05-23T15:26:11.478177+08:00"},{"id":2629,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 74d3018f-4e23-4687-8bf4-7fb403f479f7","gmt_create":"2026-05-23T15:26:11.479896+08:00","gmt_modified":"2026-05-23T15:26:11.479896+08:00"},{"id":2630,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"737f8d6c-bd8f-4c11-b142-71a400423323","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e 737f8d6c-bd8f-4c11-b142-71a400423323","gmt_create":"2026-05-23T15:26:11.481543+08:00","gmt_modified":"2026-05-23T15:26:11.481543+08:00"},{"id":2631,"source_id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","target_id":"ae62f4a8-8840-4c8e-9a42-3373370299ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 49915365-e38e-43b5-beac-6aa7d5a74cbb -\u003e ae62f4a8-8840-4c8e-9a42-3373370299ff","gmt_create":"2026-05-23T15:26:11.483862+08:00","gmt_modified":"2026-05-23T15:26:11.483862+08:00"},{"id":2632,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e 1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","gmt_create":"2026-05-23T15:26:11.485457+08:00","gmt_modified":"2026-05-23T15:26:11.485458+08:00"},{"id":2633,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"26f80935-eac2-44ee-bcdb-d6a79c537750","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e 26f80935-eac2-44ee-bcdb-d6a79c537750","gmt_create":"2026-05-23T15:26:11.486443+08:00","gmt_modified":"2026-05-23T15:26:11.486443+08:00"},{"id":2634,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"eb1288f7-5ea1-413a-8f54-4f870306d14d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e eb1288f7-5ea1-413a-8f54-4f870306d14d","gmt_create":"2026-05-23T15:26:11.487483+08:00","gmt_modified":"2026-05-23T15:26:11.487483+08:00"},{"id":2635,"source_id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","target_id":"aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 98909ecc-fceb-4ab7-a26f-741838eb2e50 -\u003e aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","gmt_create":"2026-05-23T15:26:11.48887+08:00","gmt_modified":"2026-05-23T15:26:11.48887+08:00"},{"id":2636,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"13c568d2-dfa7-4d1b-81c0-dfef247cbb67","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 13c568d2-dfa7-4d1b-81c0-dfef247cbb67","gmt_create":"2026-05-23T15:26:11.490522+08:00","gmt_modified":"2026-05-23T15:26:11.490522+08:00"},{"id":2637,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"222a9371-45c1-4e0d-b1da-e8ada1c501c2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 222a9371-45c1-4e0d-b1da-e8ada1c501c2","gmt_create":"2026-05-23T15:26:11.492226+08:00","gmt_modified":"2026-05-23T15:26:11.492226+08:00"},{"id":2638,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"979be617-a83d-4db9-b73e-38581348f8c1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 979be617-a83d-4db9-b73e-38581348f8c1","gmt_create":"2026-05-23T15:26:11.493178+08:00","gmt_modified":"2026-05-23T15:26:11.493178+08:00"},{"id":2639,"source_id":"643984fc-5a57-498b-8f25-68cc318d9d82","target_id":"422c46b3-e69c-4023-a878-411a48ae182f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 643984fc-5a57-498b-8f25-68cc318d9d82 -\u003e 422c46b3-e69c-4023-a878-411a48ae182f","gmt_create":"2026-05-23T15:26:11.494227+08:00","gmt_modified":"2026-05-23T15:26:11.494227+08:00"},{"id":2640,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","gmt_create":"2026-05-23T15:26:11.495508+08:00","gmt_modified":"2026-05-23T15:26:11.495508+08:00"},{"id":2641,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"8c17b44f-1586-459b-a83d-c9b961cd2142","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 8c17b44f-1586-459b-a83d-c9b961cd2142","gmt_create":"2026-05-23T15:26:11.49656+08:00","gmt_modified":"2026-05-23T15:26:11.49656+08:00"},{"id":2642,"source_id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","target_id":"05e59a75-d52f-42e1-a924-f6a32f06f2fe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0c36b2b-bb03-4624-933d-c1f6a320b7ca -\u003e 05e59a75-d52f-42e1-a924-f6a32f06f2fe","gmt_create":"2026-05-23T15:26:11.497857+08:00","gmt_modified":"2026-05-23T15:26:11.497857+08:00"},{"id":2643,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"d2c7157d-157f-4990-8f76-11f3ea5435f7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e d2c7157d-157f-4990-8f76-11f3ea5435f7","gmt_create":"2026-05-23T15:26:11.499867+08:00","gmt_modified":"2026-05-23T15:26:11.499867+08:00"},{"id":2644,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e1e0bd0e-01b3-4543-9781-d9beb32b9a57","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e e1e0bd0e-01b3-4543-9781-d9beb32b9a57","gmt_create":"2026-05-23T15:26:11.501613+08:00","gmt_modified":"2026-05-23T15:26:11.501613+08:00"},{"id":2645,"source_id":"c5849940-e223-4222-be17-aa0a6cb36bc8","target_id":"e9a02c86-236b-49cb-bbed-9462ee123c04","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c5849940-e223-4222-be17-aa0a6cb36bc8 -\u003e e9a02c86-236b-49cb-bbed-9462ee123c04","gmt_create":"2026-05-23T15:26:11.502659+08:00","gmt_modified":"2026-05-23T15:26:11.502659+08:00"},{"id":2646,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"ec2f1708-d31e-42bb-8959-fa405db7d6da","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e ec2f1708-d31e-42bb-8959-fa405db7d6da","gmt_create":"2026-05-23T15:26:11.525084+08:00","gmt_modified":"2026-05-23T15:26:11.525084+08:00"},{"id":2647,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2059d1cd-98a3-4b7f-b29b-69acf8a0d751","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e 2059d1cd-98a3-4b7f-b29b-69acf8a0d751","gmt_create":"2026-05-23T15:26:11.526803+08:00","gmt_modified":"2026-05-23T15:26:11.526803+08:00"},{"id":2648,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"d474a7a6-e056-4456-ba79-4aedbb7add58","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e d474a7a6-e056-4456-ba79-4aedbb7add58","gmt_create":"2026-05-23T15:26:11.528146+08:00","gmt_modified":"2026-05-23T15:26:11.528146+08:00"},{"id":2649,"source_id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","target_id":"2d7c030d-7b82-418c-9a16-67b067cac93c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1c4316a1-f1d7-46da-bcfc-ea2fa0c56110 -\u003e 2d7c030d-7b82-418c-9a16-67b067cac93c","gmt_create":"2026-05-23T15:26:11.529536+08:00","gmt_modified":"2026-05-23T15:26:11.529537+08:00"}],"source_files":[{"id":"12e2c3d7b9a92dc44a6ee29b85e10df6","path":"frontend/app/layout.tsx","filename":"layout.tsx","gmt_create":"2026-04-23T15:19:43.754128+08:00","gmt_modified":"2026-04-23T15:19:43.754129+08:00"},{"id":"2a1c745c7b3fb7f600596be3d979bba1","path":"frontend/app/(dashboard","filename":"(dashboard","gmt_create":"2026-04-23T15:19:43.756075+08:00","gmt_modified":"2026-04-23T15:19:43.756075+08:00"},{"id":"eca13a610badfc5ffc6210827fb96991","path":"frontend/components/layout/header.tsx","filename":"header.tsx","gmt_create":"2026-04-23T15:19:43.756308+08:00","gmt_modified":"2026-04-23T15:19:43.756308+08:00"},{"id":"18a0651d895fba9bb4e0c0229459efdc","path":"frontend/components/layout/sidebar.tsx","filename":"sidebar.tsx","gmt_create":"2026-04-23T15:19:43.756496+08:00","gmt_modified":"2026-04-23T15:19:43.756496+08:00"},{"id":"5d7886d0dc99f81073a578b8aefdd375","path":"frontend/lib/api.ts","filename":"api.ts","gmt_create":"2026-04-23T15:19:43.756648+08:00","gmt_modified":"2026-04-23T15:19:43.756648+08:00"},{"id":"0c0b0f4e2cf44facd9d5b57de0d0bf0c","path":"frontend/components/ui/table.tsx","filename":"table.tsx","gmt_create":"2026-04-23T15:19:43.758184+08:00","gmt_modified":"2026-04-23T15:19:43.758184+08:00"},{"id":"108b0c4b4dcfb6aa39a5eb138225c148","path":"frontend/components/ui/dialog.tsx","filename":"dialog.tsx","gmt_create":"2026-04-23T15:19:43.75905+08:00","gmt_modified":"2026-04-23T15:19:43.75905+08:00"},{"id":"ef72f0c3cedb9fd9a87352fe493053dc","path":"frontend/lib/platforms.ts","filename":"platforms.ts","gmt_create":"2026-04-23T15:19:43.759223+08:00","gmt_modified":"2026-04-23T15:19:43.759223+08:00"},{"id":"f93ae024fe0a2e69698037dff6df205f","path":"frontend/lib/utils.ts","filename":"utils.ts","gmt_create":"2026-04-23T15:19:43.759351+08:00","gmt_modified":"2026-04-23T15:19:43.759351+08:00"},{"id":"d5f2266643d2011c66e86af088ec637f","path":"frontend/components/charts/trend-chart.tsx","filename":"trend-chart.tsx","gmt_create":"2026-04-23T15:19:43.759489+08:00","gmt_modified":"2026-04-23T15:19:43.759489+08:00"},{"id":"f1a7d61831cc0a45ac6220294f15c21d","path":"frontend/components/charts/platform-chart.tsx","filename":"platform-chart.tsx","gmt_create":"2026-04-23T15:19:43.759606+08:00","gmt_modified":"2026-04-23T15:19:43.759606+08:00"},{"id":"9228ff67d4c757a85d9421b71f4b29f5","path":"backend/app/main.py","filename":"main.py","gmt_create":"2026-04-23T15:19:45.5873+08:00","gmt_modified":"2026-04-23T15:19:45.5873+08:00"},{"id":"93022c8938ce318f167277cfa65c29a7","path":"backend/app/api/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.587785+08:00","gmt_modified":"2026-04-23T15:19:45.587786+08:00"},{"id":"6b3d903205941aa9391dd90016e1102c","path":"backend/app/api/queries.py","filename":"queries.py","gmt_create":"2026-04-23T15:19:45.588167+08:00","gmt_modified":"2026-04-23T15:19:45.588167+08:00"},{"id":"7538ffe4902ab6041adb28b19844962a","path":"backend/app/api/citations.py","filename":"citations.py","gmt_create":"2026-04-23T15:19:45.588473+08:00","gmt_modified":"2026-04-23T15:19:45.588473+08:00"},{"id":"58901c94d975d87e652a4dc6c8dda656","path":"backend/app/api/reports.py","filename":"reports.py","gmt_create":"2026-04-23T15:19:45.588695+08:00","gmt_modified":"2026-04-23T15:19:45.588695+08:00"},{"id":"9d08667997a868fc07c9b4e328e44224","path":"backend/app/api/deps.py","filename":"deps.py","gmt_create":"2026-04-23T15:19:45.588857+08:00","gmt_modified":"2026-04-23T15:19:45.588857+08:00"},{"id":"e0c0ca66b8b81cf66e078a7ab162c07f","path":"backend/app/schemas/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.589011+08:00","gmt_modified":"2026-04-23T15:19:45.589011+08:00"},{"id":"f301b79d833233ce39d350e82a71c938","path":"backend/app/schemas/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.589202+08:00","gmt_modified":"2026-04-23T15:19:45.589202+08:00"},{"id":"1a3336b4af8a39a055e912724338580c","path":"backend/app/schemas/citation.py","filename":"citation.py","gmt_create":"2026-04-23T15:19:45.589399+08:00","gmt_modified":"2026-04-23T15:19:45.589399+08:00"},{"id":"4d2f3847b7c10634733118b70a1aea0b","path":"backend/app/services/auth.py","filename":"auth.py","gmt_create":"2026-04-23T15:19:45.589591+08:00","gmt_modified":"2026-04-23T15:19:45.589591+08:00"},{"id":"88d22de3b2a7419868e8ae19130d860c","path":"backend/app/services/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.589732+08:00","gmt_modified":"2026-04-23T15:19:45.589732+08:00"},{"id":"04e3926c080e795713bff683e7dc9d3e","path":"backend/app/services/citation.py","filename":"citation.py","gmt_create":"2026-04-23T15:19:45.589852+08:00","gmt_modified":"2026-04-23T15:19:45.589852+08:00"},{"id":"9ff19022ef915615911280e3c49ed44b","path":"backend/app/config.py","filename":"config.py","gmt_create":"2026-04-23T15:19:45.589987+08:00","gmt_modified":"2026-04-23T15:19:45.589987+08:00"},{"id":"c59f8c276697a070dffc581fe94d809c","path":"backend/app/models/user.py","filename":"user.py","gmt_create":"2026-04-23T15:19:45.590197+08:00","gmt_modified":"2026-04-23T15:19:45.590198+08:00"},{"id":"b74caccb06844efcdb14d8324cff65c2","path":"backend/app/models/query.py","filename":"query.py","gmt_create":"2026-04-23T15:19:45.590343+08:00","gmt_modified":"2026-04-23T15:19:45.590344+08:00"},{"id":"b4a81ef789630d0af6a8d50859d01bf3","path":"backend/app/models/citation_record.py","filename":"citation_record.py","gmt_create":"2026-04-23T15:19:45.590489+08:00","gmt_modified":"2026-04-23T15:19:45.590489+08:00"},{"id":"069738f21ac2da7349d22683e8c36929","path":"backend/app/models/query_task.py","filename":"query_task.py","gmt_create":"2026-04-23T15:19:45.59062+08:00","gmt_modified":"2026-04-23T15:19:45.59062+08:00"},{"id":"5cbb1e3f112aeba62a14b0b8999fc0f5","path":"backend/app/workers/scheduler.py","filename":"scheduler.py","gmt_create":"2026-04-23T15:20:08.953491+08:00","gmt_modified":"2026-04-23T15:20:08.953491+08:00"},{"id":"74040de652d5e57f548bb5c4adc3e1a0","path":"backend/app/workers/citation_engine.py","filename":"citation_engine.py","gmt_create":"2026-04-23T15:20:08.953836+08:00","gmt_modified":"2026-04-23T15:20:08.953837+08:00"},{"id":"8f973791233c698b3e64a4fb28a93d4b","path":"backend/app/workers/platforms/kimi.py","filename":"kimi.py","gmt_create":"2026-04-23T15:20:08.954103+08:00","gmt_modified":"2026-04-23T15:20:08.954103+08:00"},{"id":"f642fc1c2f34e15572d9d98aa6c18813","path":"backend/app/workers/platforms/wenxin.py","filename":"wenxin.py","gmt_create":"2026-04-23T15:20:08.954273+08:00","gmt_modified":"2026-04-23T15:20:08.954273+08:00"},{"id":"a16cf42e9559523c4f96ca4c79f9488d","path":"backend/app/workers/platforms/base.py","filename":"base.py","gmt_create":"2026-04-23T15:20:08.954406+08:00","gmt_modified":"2026-04-23T15:20:08.954406+08:00"},{"id":"b0c428683c8a3e6922d90ca0d8c2736d","path":"backend/app/database.py","filename":"database.py","gmt_create":"2026-04-23T15:20:08.955702+08:00","gmt_modified":"2026-04-23T15:20:08.955702+08:00"},{"id":"b2f0d46a31a5441594f2e777365fc156","path":"tests/test_scheduler.py","filename":"test_scheduler.py","gmt_create":"2026-04-23T15:20:08.95621+08:00","gmt_modified":"2026-04-23T15:20:08.95621+08:00"},{"id":"0613e76b9679be7f998fb8fd8056e686","path":"tests/test_queries.py","filename":"test_queries.py","gmt_create":"2026-04-23T15:20:08.956336+08:00","gmt_modified":"2026-04-23T15:20:08.956336+08:00"},{"id":"99fe1b288fd41daa86c2dfbab819abf0","path":"backend/app/models/__init__.py","filename":"__init__.py","gmt_create":"2026-04-23T15:21:46.682639+08:00","gmt_modified":"2026-04-23T15:21:46.682639+08:00"},{"id":"bceca00463fe55d3bcafda728f97f723","path":"backend/app/models/subscription.py","filename":"subscription.py","gmt_create":"2026-04-23T15:21:46.684259+08:00","gmt_modified":"2026-04-23T15:21:46.684259+08:00"},{"id":"d4f95fcf50683b5bf6167c7d2a6b126d","path":"backend/alembic/versions/488d0bd5ab01_initial_migration.py","filename":"488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-23T15:21:46.684619+08:00","gmt_modified":"2026-04-23T15:21:46.684619+08:00"},{"id":"0ef1efea889dba3e1f299626df479571","path":"tests/conftest.py","filename":"conftest.py","gmt_create":"2026-04-23T15:22:15.981194+08:00","gmt_modified":"2026-04-23T15:22:15.981194+08:00"},{"id":"389d631bc6c7111ba411b0b79fca455e","path":"tests/test_auth.py","filename":"test_auth.py","gmt_create":"2026-04-23T15:22:15.98141+08:00","gmt_modified":"2026-04-23T15:22:15.98141+08:00"},{"id":"80a0429cc47931de27ddb17a62b8dd9c","path":"tests/test_business_flow.py","filename":"test_business_flow.py","gmt_create":"2026-04-23T15:22:15.981566+08:00","gmt_modified":"2026-04-23T15:22:15.981567+08:00"},{"id":"b07a4fb9cecbbd66a6910ccbc7651f19","path":"tests/test_citation_engine.py","filename":"test_citation_engine.py","gmt_create":"2026-04-23T15:22:15.981715+08:00","gmt_modified":"2026-04-23T15:22:15.981715+08:00"},{"id":"42ff5383133d176cec9eb88682483be3","path":"tests/test_citations.py","filename":"test_citations.py","gmt_create":"2026-04-23T15:22:15.981831+08:00","gmt_modified":"2026-04-23T15:22:15.981831+08:00"},{"id":"aaf5bce6be82d2f947bfa5c1806de452","path":"frontend/package.json","filename":"package.json","gmt_create":"2026-04-23T15:22:23.492837+08:00","gmt_modified":"2026-04-23T15:22:23.492837+08:00"},{"id":"01056dad8851d3e9bd532eb4cab33792","path":"frontend/tailwind.config.ts","filename":"tailwind.config.ts","gmt_create":"2026-04-23T15:22:23.495792+08:00","gmt_modified":"2026-04-23T15:22:23.495792+08:00"},{"id":"ac1acbc54c49ee1de13369f6c6827568","path":"frontend/components/ui/button.tsx","filename":"button.tsx","gmt_create":"2026-04-23T15:22:23.496353+08:00","gmt_modified":"2026-04-23T15:22:23.496353+08:00"},{"id":"0186dc8a89340139a84e1e3c5571a57f","path":"frontend/components/ui/dropdown-menu.tsx","filename":"dropdown-menu.tsx","gmt_create":"2026-04-23T15:22:23.496869+08:00","gmt_modified":"2026-04-23T15:22:23.496869+08:00"},{"id":"3cf787fa77a15b2b1783560c6d83ed21","path":"frontend/components/ui/input.tsx","filename":"input.tsx","gmt_create":"2026-04-23T15:22:23.497127+08:00","gmt_modified":"2026-04-23T15:22:23.497128+08:00"},{"id":"3c56e1c079959bfcc985183805e5874f","path":"frontend/components/ui/select.tsx","filename":"select.tsx","gmt_create":"2026-04-23T15:22:23.497457+08:00","gmt_modified":"2026-04-23T15:22:23.497457+08:00"},{"id":"0d5ef537f7c0b8c390f8b31d7cf47b56","path":"frontend/components/ui/card.tsx","filename":"card.tsx","gmt_create":"2026-04-23T15:22:23.497745+08:00","gmt_modified":"2026-04-23T15:22:23.497745+08:00"},{"id":"51821ca9ec2a1c972f3c9d111e19db8a","path":"frontend/components/ui/badge.tsx","filename":"badge.tsx","gmt_create":"2026-04-23T15:22:23.498034+08:00","gmt_modified":"2026-04-23T15:22:23.498034+08:00"},{"id":"beb87ab5aad9532647e9dbd2db7ef587","path":"frontend/components/ui/tabs.tsx","filename":"tabs.tsx","gmt_create":"2026-04-23T15:22:23.498711+08:00","gmt_modified":"2026-04-23T15:22:23.498711+08:00"},{"id":"792b8e2c16c9ff2095d83b8972313be4","path":"frontend/components/ui/label.tsx","filename":"label.tsx","gmt_create":"2026-04-23T15:22:23.499031+08:00","gmt_modified":"2026-04-23T15:22:23.499031+08:00"},{"id":"546e01c5f73aaf5140eee922f4b9a441","path":"frontend/components/providers.tsx","filename":"providers.tsx","gmt_create":"2026-04-23T15:22:23.499298+08:00","gmt_modified":"2026-04-23T15:22:23.499298+08:00"},{"id":"e68ad5186f1e47610ab3d9f14a794393","path":"backend/app/workers/platforms/tongyi.py","filename":"tongyi.py","gmt_create":"2026-04-23T20:31:36.476814+08:00","gmt_modified":"2026-04-23T20:31:36.476814+08:00"},{"id":"404f6d0765a8c6e77e33b7fc21b377a4","path":"backend/app/workers/platforms/doubao.py","filename":"doubao.py","gmt_create":"2026-04-23T20:31:36.477414+08:00","gmt_modified":"2026-04-23T20:31:36.477414+08:00"},{"id":"303e80519e946904d1cb3ac32cbb0814","path":"backend/app/workers/platforms/qingyan.py","filename":"qingyan.py","gmt_create":"2026-04-23T20:31:36.477731+08:00","gmt_modified":"2026-04-23T20:31:36.477731+08:00"},{"id":"5af7301fe056fc3d10820d820e8ad777","path":"backend/app/workers/platforms/tiangong.py","filename":"tiangong.py","gmt_create":"2026-04-23T20:31:36.477969+08:00","gmt_modified":"2026-04-23T20:31:36.477969+08:00"},{"id":"0e38ad5d2d3daaad08c9302df8805b15","path":"backend/app/workers/platforms/xinghuo.py","filename":"xinghuo.py","gmt_create":"2026-04-23T20:31:36.47825+08:00","gmt_modified":"2026-04-23T20:31:36.47825+08:00"},{"id":"6a63f048c16c60c5d2d57012c810ee0e","path":"backend/app/workers/platforms/search_engine.py","filename":"search_engine.py","gmt_create":"2026-04-23T20:31:36.478564+08:00","gmt_modified":"2026-04-23T20:31:36.478564+08:00"},{"id":"a26ee01cf41da3b956e1650448c156fa","path":"backend/requirements.txt","filename":"requirements.txt","gmt_create":"2026-04-23T20:31:36.48051+08:00","gmt_modified":"2026-04-23T20:31:36.48051+08:00"},{"id":"e9b52adbec3c07cf021e488dd3f99ab4","path":"backend/Dockerfile","filename":"Dockerfile","gmt_create":"2026-04-23T20:31:50.452043+08:00","gmt_modified":"2026-04-23T20:31:50.452043+08:00"},{"id":"4a56ef5fca60bc63480b457cab3832f0","path":"backend/app/workers/platforms/__init__.py","filename":"__init__.py","gmt_create":"2026-04-23T20:35:18.583102+08:00","gmt_modified":"2026-04-23T20:35:18.583102+08:00"},{"id":"36dd0ad3ee6bc75a480ad8a62268e80e","path":"backend/app/workers/models/query.py","filename":"query.py","gmt_create":"2026-04-23T20:35:18.58383+08:00","gmt_modified":"2026-04-23T20:35:18.58383+08:00"},{"id":"a680d4819f5da57fe9fa0e6bc708f380","path":"backend/alembic/env.py","filename":"env.py","gmt_create":"2026-04-23T20:35:45.568869+08:00","gmt_modified":"2026-04-23T20:35:45.56887+08:00"},{"id":"f6e6948dd0cdd3894bd9928b21feb979","path":"backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","filename":"b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py","gmt_create":"2026-04-23T20:35:45.569946+08:00","gmt_modified":"2026-04-23T20:35:45.569946+08:00"},{"id":"50f2e6bdc4a79e69bd43ea8d6fec67fe","path":"backend/alembic.ini","filename":"alembic.ini","gmt_create":"2026-04-23T20:35:45.570621+08:00","gmt_modified":"2026-04-23T20:35:45.570621+08:00"},{"id":"fc6242433ae9506bcc0bf4cb0dce1413","path":"docker-compose.yml","filename":"docker-compose.yml","gmt_create":"2026-04-23T20:35:45.574312+08:00","gmt_modified":"2026-04-23T20:35:45.574314+08:00"},{"id":"5e414f2ef9b69e55e00ab15f85b9291a","path":"frontend/Dockerfile","filename":"Dockerfile","gmt_create":"2026-04-23T21:00:59.630269+08:00","gmt_modified":"2026-04-23T21:00:59.630269+08:00"},{"id":"fb8af100a06778e1fbdac4790a3ed0a9","path":"frontend/tsconfig.json","filename":"tsconfig.json","gmt_create":"2026-04-23T21:00:59.630887+08:00","gmt_modified":"2026-04-23T21:00:59.630888+08:00"},{"id":"4d9b59c294a0aac5e300b3de715eb226","path":"frontend/.eslintrc.json","filename":".eslintrc.json","gmt_create":"2026-04-23T21:00:59.631396+08:00","gmt_modified":"2026-04-23T21:00:59.631396+08:00"},{"id":"48a560c49d2b21da327c036ec2934b96","path":"README.md","filename":"README.md","gmt_create":"2026-04-23T21:00:59.633061+08:00","gmt_modified":"2026-04-23T21:00:59.633061+08:00"},{"id":"ed630a36e81abafd12787d4095dfe8c2","path":"backend/README.md","filename":"README.md","gmt_create":"2026-04-24T10:58:35.330288+08:00","gmt_modified":"2026-04-24T10:58:35.330289+08:00"},{"id":"1cafc02d1d722feb4692dab6ae85c09f","path":"frontend/README.md","filename":"README.md","gmt_create":"2026-04-24T10:58:35.331593+08:00","gmt_modified":"2026-04-24T10:58:35.331593+08:00"},{"id":"d2c1984414de6856ed5b3873c661b712","path":"frontend/lib/auth.ts","filename":"auth.ts","gmt_create":"2026-04-24T10:58:35.334476+08:00","gmt_modified":"2026-04-24T10:58:35.334477+08:00"},{"id":"f26740f2a1532b38c816663a4f665dbf","path":"backend/app/api/admin.py","filename":"admin.py","gmt_create":"2026-04-24T10:58:51.055493+08:00","gmt_modified":"2026-04-24T10:58:51.055493+08:00"},{"id":"5386144bf3c668c6fa14481c0d85a214","path":"backend/app/api/subscriptions.py","filename":"subscriptions.py","gmt_create":"2026-04-24T10:58:51.055792+08:00","gmt_modified":"2026-04-24T10:58:51.055792+08:00"},{"id":"b44632a0f399b2fe2b4daf295a120ec7","path":"backend/app/middleware/logging_middleware.py","filename":"logging_middleware.py","gmt_create":"2026-04-24T10:58:51.05617+08:00","gmt_modified":"2026-04-24T10:58:51.056171+08:00"},{"id":"5883a8ef4fc156d76b71ffdb5ecdf232","path":"backend/app/middleware/rate_limit.py","filename":"rate_limit.py","gmt_create":"2026-04-24T10:58:51.056416+08:00","gmt_modified":"2026-04-24T10:58:51.056416+08:00"},{"id":"5013cbe89f1c6f03533eb218400cedb0","path":"backend/app/schemas/subscription.py","filename":"subscription.py","gmt_create":"2026-04-24T10:58:51.056765+08:00","gmt_modified":"2026-04-24T10:58:51.056765+08:00"},{"id":"3809c5ab912511e0e093ba02a4fc918f","path":"backend/app/services/admin.py","filename":"admin.py","gmt_create":"2026-04-24T10:58:51.058083+08:00","gmt_modified":"2026-04-24T10:58:51.058083+08:00"},{"id":"b250fc6c32106a7f3e0c3ad152dfc097","path":"backend/app/services/subscription.py","filename":"subscription.py","gmt_create":"2026-04-24T10:58:51.058233+08:00","gmt_modified":"2026-04-24T10:58:51.058233+08:00"},{"id":"b0cb6810919f64006be7aa66b2b76a61","path":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py","filename":"c3d5e7f9ab12_add_user_management_fields.py","gmt_create":"2026-04-24T10:59:38.893705+08:00","gmt_modified":"2026-04-24T10:59:38.893705+08:00"},{"id":"955e1dfe57f0a9a8e900383eb7641ba1","path":"frontend/next.config.mjs","filename":"next.config.mjs","gmt_create":"2026-04-24T11:01:58.061252+08:00","gmt_modified":"2026-04-24T11:01:58.061252+08:00"},{"id":"5800a08224424ebced854d06365f6d44","path":"frontend/app/(auth","filename":"(auth","gmt_create":"2026-04-24T11:01:58.062019+08:00","gmt_modified":"2026-04-24T11:01:58.062019+08:00"},{"id":"b1d80d63eae8fd5e1bdfeee3c6bc9594","path":"frontend/types/next-auth.d.ts","filename":"next-auth.d.ts","gmt_create":"2026-04-24T11:01:58.062472+08:00","gmt_modified":"2026-04-24T11:01:58.062472+08:00"},{"id":"facea1f00ec72e00f774d0839fee7131","path":"#wiki#main#wiki#zh/[app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","filename":"route.ts)","gmt_create":"2026-04-24T11:01:58.064844+08:00","gmt_modified":"2026-04-24T11:01:58.064845+08:00"},{"id":"37d7291b1373216dcf08f081a94ab1c8","path":"#wiki#main#wiki#zh/[frontend/app/api/auth/[...nextauth]/route.ts](file:/frontend/app/api/auth/[...nextauth]/route.ts)","filename":"route.ts)","gmt_create":"2026-04-24T11:02:17.54199+08:00","gmt_modified":"2026-04-24T11:02:17.54199+08:00"},{"id":"1eb698126da2b6c95924e3ca32115e3a","path":"tests/test_content_agents.py","filename":"test_content_agents.py","gmt_create":"2026-05-23T15:16:36.136354+08:00","gmt_modified":"2026-05-23T15:16:36.136354+08:00"},{"id":"ff5699698ead454bb1137030cf21c533","path":"tests/test_llm_provider.py","filename":"test_llm_provider.py","gmt_create":"2026-05-23T15:16:36.136596+08:00","gmt_modified":"2026-05-23T15:16:36.136596+08:00"},{"id":"a8bfbe8f5db65abf625c19edc3999a97","path":"tests/test_pipeline_engine.py","filename":"test_pipeline_engine.py","gmt_create":"2026-05-23T15:16:36.136778+08:00","gmt_modified":"2026-05-23T15:16:36.136779+08:00"},{"id":"0bfe423695374ece56313bb55e9d3e86","path":"tests/test_platform_rules.py","filename":"test_platform_rules.py","gmt_create":"2026-05-23T15:16:36.136934+08:00","gmt_modified":"2026-05-23T15:16:36.136934+08:00"},{"id":"bbcb3a67f564dd7c05d3f8684c9bf8c6","path":"tests/test_prompt_template.py","filename":"test_prompt_template.py","gmt_create":"2026-05-23T15:16:36.137095+08:00","gmt_modified":"2026-05-23T15:16:36.137095+08:00"},{"id":"2aab65d07faab01583455277d363742f","path":"tests/test_rag_service.py","filename":"test_rag_service.py","gmt_create":"2026-05-23T15:16:36.137516+08:00","gmt_modified":"2026-05-23T15:16:36.137516+08:00"},{"id":"af7c8d3b4ba659f1bd8c4989b5ed7a62","path":"backend/tests/test_integration/test_full_flow.py","filename":"test_full_flow.py","gmt_create":"2026-05-23T15:16:36.138034+08:00","gmt_modified":"2026-05-23T15:16:36.138034+08:00"},{"id":"13b8f594e7cace5c8a9255dc801dcad8","path":"backend/app/agent_framework/agents/content_generator_agent.py","filename":"content_generator_agent.py","gmt_create":"2026-05-23T15:16:36.140513+08:00","gmt_modified":"2026-05-23T15:16:36.140513+08:00"},{"id":"750f8d79d83ee910e9d18e8a4fe37e22","path":"backend/app/agent_framework/agents/deai_agent.py","filename":"deai_agent.py","gmt_create":"2026-05-23T15:16:36.1407+08:00","gmt_modified":"2026-05-23T15:16:36.1407+08:00"},{"id":"7f8c6e94ead45ad9bab8cea9a7be2123","path":"backend/app/agent_framework/agents/geo_optimizer_agent.py","filename":"geo_optimizer_agent.py","gmt_create":"2026-05-23T15:16:36.140854+08:00","gmt_modified":"2026-05-23T15:16:36.140854+08:00"},{"id":"609a02c9e1ccc0311885a70578b86386","path":"backend/app/agent_framework/pipeline/engine.py","filename":"engine.py","gmt_create":"2026-05-23T15:16:36.141011+08:00","gmt_modified":"2026-05-23T15:16:36.141011+08:00"},{"id":"43642bd7bedabd97ff2f0a902b783e4e","path":"backend/app/agent_framework/pipeline/loader.py","filename":"loader.py","gmt_create":"2026-05-23T15:16:36.141161+08:00","gmt_modified":"2026-05-23T15:16:36.141161+08:00"},{"id":"1de27749fbccdfaf785545657f58d256","path":"backend/app/services/llm/factory.py","filename":"factory.py","gmt_create":"2026-05-23T15:16:36.141304+08:00","gmt_modified":"2026-05-23T15:16:36.141304+08:00"},{"id":"6a9387dd3885cf4d27bce3db87fd61c7","path":"backend/app/api/agents.py","filename":"agents.py","gmt_create":"2026-05-23T15:17:24.081191+08:00","gmt_modified":"2026-05-23T15:17:24.081192+08:00"},{"id":"9af41884bf42d6e175163e89f663a479","path":"backend/app/api/analytics.py","filename":"analytics.py","gmt_create":"2026-05-23T15:17:24.081515+08:00","gmt_modified":"2026-05-23T15:17:24.081515+08:00"},{"id":"9c224bb80474867f8ded674babaa6e11","path":"backend/app/api/lifecycle.py","filename":"lifecycle.py","gmt_create":"2026-05-23T15:17:24.081772+08:00","gmt_modified":"2026-05-23T15:17:24.081772+08:00"},{"id":"63953ee6b39f159a61963104ac06f283","path":"backend/app/api/knowledge.py","filename":"knowledge.py","gmt_create":"2026-05-23T15:17:24.082157+08:00","gmt_modified":"2026-05-23T15:17:24.082157+08:00"},{"id":"6940047dd4c29a8a219b1b50e358f7c1","path":"backend/app/schemas/analytics.py","filename":"analytics.py","gmt_create":"2026-05-23T15:17:24.084817+08:00","gmt_modified":"2026-05-23T15:17:24.084817+08:00"},{"id":"952c887faf6f91370b174bd4e1ad6e00","path":"backend/app/schemas/lifecycle.py","filename":"lifecycle.py","gmt_create":"2026-05-23T15:17:24.085312+08:00","gmt_modified":"2026-05-23T15:17:24.085312+08:00"},{"id":"ed4505205a22ba55c7d4a83b0b24eaa4","path":"backend/app/schemas/knowledge.py","filename":"knowledge.py","gmt_create":"2026-05-23T15:17:24.085541+08:00","gmt_modified":"2026-05-23T15:17:24.085541+08:00"},{"id":"a0c569cd2355079f9f4045a198ddcadc","path":"backend/app/services/analytics/insights.py","filename":"insights.py","gmt_create":"2026-05-23T15:17:24.087528+08:00","gmt_modified":"2026-05-23T15:17:24.087528+08:00"},{"id":"984d67382822ff587452a79f89e0d336","path":"backend/app/services/analytics/tracker.py","filename":"tracker.py","gmt_create":"2026-05-23T15:17:24.087949+08:00","gmt_modified":"2026-05-23T15:17:24.087949+08:00"},{"id":"45c9d96513947cae445aaaf8b58b4266","path":"backend/app/services/knowledge/rag_service.py","filename":"rag_service.py","gmt_create":"2026-05-23T15:17:24.088178+08:00","gmt_modified":"2026-05-23T15:17:24.088178+08:00"},{"id":"3b13f3fa9b6316b23cfd01d740a85b81","path":"backend/app/services/knowledge/chunker.py","filename":"chunker.py","gmt_create":"2026-05-23T15:17:24.088359+08:00","gmt_modified":"2026-05-23T15:17:24.088359+08:00"},{"id":"aaa9ce5fdaad8eaa6887e8c079e0b7af","path":"backend/app/services/knowledge/embedder.py","filename":"embedder.py","gmt_create":"2026-05-23T15:17:24.088522+08:00","gmt_modified":"2026-05-23T15:17:24.088522+08:00"},{"id":"000702af850583bb79fec57f7fd1fcca","path":"backend/app/services/knowledge/retriever.py","filename":"retriever.py","gmt_create":"2026-05-23T15:17:24.088674+08:00","gmt_modified":"2026-05-23T15:17:24.088674+08:00"},{"id":"aa6cf63a65ebf46a29606af91112eb7b","path":"backend/app/models/agent.py","filename":"agent.py","gmt_create":"2026-05-23T15:17:24.090372+08:00","gmt_modified":"2026-05-23T15:17:24.090373+08:00"},{"id":"97cfe961cb7386b4022a51706ae8f5dd","path":"backend/app/models/lifecycle.py","filename":"lifecycle.py","gmt_create":"2026-05-23T15:17:24.090637+08:00","gmt_modified":"2026-05-23T15:17:24.090638+08:00"},{"id":"4774aadaa8ace576601bdaa8d3e11f74","path":"backend/app/models/knowledge.py","filename":"knowledge.py","gmt_create":"2026-05-23T15:17:24.090925+08:00","gmt_modified":"2026-05-23T15:17:24.090925+08:00"},{"id":"3a1e34b542590c287768482d964dc7d5","path":"docs/03-development/coding-standards.md","filename":"coding-standards.md","gmt_create":"2026-05-23T15:18:41.055279+08:00","gmt_modified":"2026-05-23T15:18:41.055279+08:00"},{"id":"53d01851ef76ade6cb41a3cbe140676f","path":"docs/03-development/dev-guide.md","filename":"dev-guide.md","gmt_create":"2026-05-23T15:18:41.055638+08:00","gmt_modified":"2026-05-23T15:18:41.055638+08:00"},{"id":"21e6700955fa049df458cee6020cf073","path":"docs/05-deployment/deployment-guide.md","filename":"deployment-guide.md","gmt_create":"2026-05-23T15:18:41.055945+08:00","gmt_modified":"2026-05-23T15:18:41.055945+08:00"},{"id":"b0db309ae449a2a435fc77103ca76955","path":"docs/04-testing/test-strategy.md","filename":"test-strategy.md","gmt_create":"2026-05-23T15:18:41.056328+08:00","gmt_modified":"2026-05-23T15:18:41.056328+08:00"},{"id":"974abe01413cc7a8a4898621e0b0779e","path":"docs/03-development/tdd-workflow.md","filename":"tdd-workflow.md","gmt_create":"2026-05-23T15:18:41.056789+08:00","gmt_modified":"2026-05-23T15:18:41.056789+08:00"},{"id":"01a3a8e0d02ddfa2e64837790ba231fa","path":"docs/00-project/tech-stack.md","filename":"tech-stack.md","gmt_create":"2026-05-23T15:18:41.057096+08:00","gmt_modified":"2026-05-23T15:18:41.057096+08:00"},{"id":"68688ca664c7df5d64153200455dd7f6","path":"backend/app/models/analytics.py","filename":"analytics.py","gmt_create":"2026-05-23T15:19:23.472665+08:00","gmt_modified":"2026-05-23T15:19:23.472665+08:00"},{"id":"9bad7097cce919cde648d435f673bac1","path":"backend/app/models/alert.py","filename":"alert.py","gmt_create":"2026-05-23T15:19:23.472906+08:00","gmt_modified":"2026-05-23T15:19:23.472906+08:00"},{"id":"daab5d62bc9559915da6c4bd52dcec91","path":"backend/alembic/versions/d4f6g8h0ab23_add_geo_lifecycle_tables.py","filename":"d4f6g8h0ab23_add_geo_lifecycle_tables.py","gmt_create":"2026-05-23T15:19:23.474868+08:00","gmt_modified":"2026-05-23T15:19:23.474868+08:00"},{"id":"22a884dd0b02fa904cd2808646d4aeca","path":"backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","filename":"e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py","gmt_create":"2026-05-23T15:19:23.476036+08:00","gmt_modified":"2026-05-23T15:19:23.476036+08:00"},{"id":"e029becbf7babac61765f6a1790e1d48","path":"backend/alembic/versions/e5f7g9h1cd45_add_knowledge_base_tables.py","filename":"e5f7g9h1cd45_add_knowledge_base_tables.py","gmt_create":"2026-05-23T15:19:23.476457+08:00","gmt_modified":"2026-05-23T15:19:23.476457+08:00"},{"id":"0c2c0c0ef594628c812c0adda8b914ea","path":"backend/alembic/versions/f6g8h0i2de56_add_analytics_tables.py","filename":"f6g8h0i2de56_add_analytics_tables.py","gmt_create":"2026-05-23T15:19:23.477615+08:00","gmt_modified":"2026-05-23T15:19:23.477615+08:00"},{"id":"80f3f2a6213e0002803247e1c51233be","path":"backend/app/api/alerts.py","filename":"alerts.py","gmt_create":"2026-05-23T15:19:23.481478+08:00","gmt_modified":"2026-05-23T15:19:23.481478+08:00"},{"id":"9ea18740e615a926960e829e8c583175","path":"frontend/playwright.config.ts","filename":"playwright.config.ts","gmt_create":"2026-05-23T15:22:58.299607+08:00","gmt_modified":"2026-05-23T15:22:58.299607+08:00"},{"id":"6f639c813a6c2a20c0c05939222f7475","path":"frontend/e2e/tests/dashboard-health.spec.ts","filename":"dashboard-health.spec.ts","gmt_create":"2026-05-23T15:22:58.299977+08:00","gmt_modified":"2026-05-23T15:22:58.299977+08:00"},{"id":"a3a308292fda7895bf49445c417df345","path":"frontend/e2e/tests/login.spec.ts","filename":"login.spec.ts","gmt_create":"2026-05-23T15:22:58.300354+08:00","gmt_modified":"2026-05-23T15:22:58.300354+08:00"},{"id":"4edcf9364f826cf2a7b686447777cc07","path":"frontend/e2e/pages/dashboard.page.ts","filename":"dashboard.page.ts","gmt_create":"2026-05-23T15:22:58.300735+08:00","gmt_modified":"2026-05-23T15:22:58.300736+08:00"},{"id":"f6784e54bb91b7daa9c76653ba1b2c75","path":"frontend/e2e/pages/login.page.ts","filename":"login.page.ts","gmt_create":"2026-05-23T15:22:58.30103+08:00","gmt_modified":"2026-05-23T15:22:58.30103+08:00"},{"id":"1fa69729b52f34bc96b687a395501734","path":"frontend/components/business/index.ts","filename":"index.ts","gmt_create":"2026-05-23T15:22:58.301363+08:00","gmt_modified":"2026-05-23T15:22:58.301363+08:00"},{"id":"ebcf5e1a8abb3ccc9196e5749461f46b","path":"frontend/components/business/agent-status-card.tsx","filename":"agent-status-card.tsx","gmt_create":"2026-05-23T15:22:58.301788+08:00","gmt_modified":"2026-05-23T15:22:58.301789+08:00"},{"id":"0da5aaee978edabdfebab3a8e67d803f","path":"frontend/components/business/alert-card.tsx","filename":"alert-card.tsx","gmt_create":"2026-05-23T15:22:58.302198+08:00","gmt_modified":"2026-05-23T15:22:58.302198+08:00"},{"id":"0130bb8ebb0800faff59f36c5625b7f7","path":"frontend/components/dashboard/index.ts","filename":"index.ts","gmt_create":"2026-05-23T15:22:58.302547+08:00","gmt_modified":"2026-05-23T15:22:58.302547+08:00"},{"id":"d9f509d2a91b503397e98066751ead0c","path":"backend/app/agent_framework/agents/__init__.py","filename":"__init__.py","gmt_create":"2026-05-23T15:23:21.347893+08:00","gmt_modified":"2026-05-23T15:23:21.347894+08:00"},{"id":"58a2f69ec5607ac5e4ab93266534ac01","path":"backend/app/agent_framework/agents/citation_detector.py","filename":"citation_detector.py","gmt_create":"2026-05-23T15:23:21.349766+08:00","gmt_modified":"2026-05-23T15:23:21.349766+08:00"},{"id":"fcde401daccbe6de50f3829f021ecf55","path":"backend/app/agent_framework/dispatcher.py","filename":"dispatcher.py","gmt_create":"2026-05-23T15:23:21.355483+08:00","gmt_modified":"2026-05-23T15:23:21.355483+08:00"},{"id":"5b011956f30d4ac51420444cca8c7f08","path":"backend/workers/scheduler.py","filename":"scheduler.py","gmt_create":"2026-05-23T15:23:21.360698+08:00","gmt_modified":"2026-05-23T15:23:21.360699+08:00"},{"id":"4d4403d720ed0580f3ed57503b584eff","path":"backend/workers/citation_engine.py","filename":"citation_engine.py","gmt_create":"2026-05-23T15:23:21.36113+08:00","gmt_modified":"2026-05-23T15:23:21.36113+08:00"},{"id":"8aa6b45626f9eb93a3f4fbf1d3206a38","path":"backend/workers/platforms/base.py","filename":"base.py","gmt_create":"2026-05-23T15:23:21.362039+08:00","gmt_modified":"2026-05-23T15:23:21.36204+08:00"},{"id":"21ab29cd896c5703dfa3461a055c0f54","path":"frontend/lib/api/lifecycle.ts","filename":"lifecycle.ts","gmt_create":"2026-05-23T15:23:21.375132+08:00","gmt_modified":"2026-05-23T15:23:21.375132+08:00"},{"id":"ca1e69e3279cea977bb7f660d417b4d8","path":"backend/app/workers/llm_adapter.py","filename":"llm_adapter.py","gmt_create":"2026-05-23T15:24:01.680615+08:00","gmt_modified":"2026-05-23T15:24:01.680616+08:00"},{"id":"249d68c4ba50c523b617a8c82e7afdae","path":"backend/app/agent_framework/base.py","filename":"base.py","gmt_create":"2026-05-23T15:24:01.681072+08:00","gmt_modified":"2026-05-23T15:24:01.681072+08:00"},{"id":"5d2b9655ba99a14a3accb1878bb5681a","path":"backend/app/agent_framework/registry.py","filename":"registry.py","gmt_create":"2026-05-23T15:24:01.682376+08:00","gmt_modified":"2026-05-23T15:24:01.682376+08:00"},{"id":"022c381f121cc2a65834024ca2c9b8c1","path":"backend/app/agent_framework/pipeline/schema.py","filename":"schema.py","gmt_create":"2026-05-23T15:24:01.684475+08:00","gmt_modified":"2026-05-23T15:24:01.684475+08:00"},{"id":"3a2a43dd94c9405ea91934c43cdecced","path":"backend/app/agent_framework/protocol.py","filename":"protocol.py","gmt_create":"2026-05-23T15:24:01.685073+08:00","gmt_modified":"2026-05-23T15:24:01.685073+08:00"},{"id":"fffc152ed28771e8a42e5bb2e33650cd","path":"backend/pipelines/content_production.yaml","filename":"content_production.yaml","gmt_create":"2026-05-23T15:24:01.688276+08:00","gmt_modified":"2026-05-23T15:24:01.688276+08:00"},{"id":"856c9e5eddcb40682e653dbd1a4bfc4b","path":"backend/pipelines/diagnosis.yaml","filename":"diagnosis.yaml","gmt_create":"2026-05-23T15:24:01.688961+08:00","gmt_modified":"2026-05-23T15:24:01.688961+08:00"},{"id":"aa21995469cad3e13897d5dbe268533f","path":"frontend/lib/api/agents.ts","filename":"agents.ts","gmt_create":"2026-05-23T15:26:09.814653+08:00","gmt_modified":"2026-05-23T15:26:09.814654+08:00"},{"id":"6b50314c917457b8b70ade390573c3cb","path":"backend/app/agent_framework/config_manager.py","filename":"config_manager.py","gmt_create":"2026-05-23T15:26:09.824114+08:00","gmt_modified":"2026-05-23T15:26:09.824114+08:00"},{"id":"c2036406c4a0ae8b1e671ef1f1601826","path":".env.example","filename":".env.example","gmt_create":"2026-05-23T15:26:09.827338+08:00","gmt_modified":"2026-05-23T15:26:09.827339+08:00"}],"wiki_catalogs":[{"id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"项目概述","description":"project-overview","prompt":"为GEO项目创建全面的项目概述内容。详细介绍GEO平台的核心目标、主要功能特性和技术架构。解释项目作为智能学术查询与引用管理系统的设计理念,包括多AI平台集成、定时查询任务调度、数据可视化展示等核心功能。说明前后端技术栈的选择原因和整体架构设计思路。提供项目背景、应用场景和价值主张。包含系统边界、核心组件关系图和数据流向说明。面向初学者提供概念性理解,同时为经验丰富的开发者提供技术决策的背景信息。","progress_status":"completed","dependent_files":"backend/README.md,frontend/README.md,backend/app/main.py,backend/app/config.py,docker-compose.yml,README.md","gmt_create":"2026-04-22T18:56:47.080895+08:00","gmt_modified":"2026-04-24T10:58:35.431076+08:00","raw_data":"WikiEncrypted:nzQO5jvliy8ncyK0FT40s3j/+jLrEduTcrc/mlxpgSLdYjBwtNztvkbMoPPMFNEMDes7QSOWotr7g4sRG3hN1QC5esoYS3BvN6Y/T/6GOvnwo5Ww+L13yRESwkAhTxZ0bDtqMqBMDJjp0MKl68qbq7B2U5OjVB5vyO1G7qlX+bY4a+E+zpn1E17PQvN9P7VlQgVDqa1nwz8U0c4YkUjlvSLoRXqMUPWbTTo8enr8varFiB9kZhlIveqWyQg70c2so+mmgK5tu58aGpglpVdjphh9cbkx8+rqqdDcytUZT7S8pKc4MGkZe3rCbq6nyT0QAyu8WwZ0h9/zER3M3mecpY0QwlpWFcQiEekYeGeusO+eNSbtIN9Tohtik8zfV/pV0TaGc/LbnkcMtj8m0T83c8wKIfYs/liR225bzfnhLIqsoF6rOnXNLIoTpE8Z6Ks8+5swWOqw0Oa1WUgNMnH79HbG7z2uBctEg3Kb/3wmXweL49APkVOhhX9rJu18yc8nR26giaoFIlCpKme7nOHGBbxVcV8/JH1uRvSJLspnk9+gwQcK6n07+/KN5SIq/dFPZUVljWill5+4lQiNxtX+bZcGsWdNjyiate8dGLZoiydoxbt8zaaOQ/sE/vzpNhUqORGkQ8zSh8rLkJEdzSYUCb95gUWs+6vCBogO7GSPqHQcoYZi5WnndLvZiktMpSEJFxGL8OBQQmyD6Z6bOiznhTf01DdqjQOJBP1sIfkt1trL9OQOr20Ak7fnYetRoaFaSlNhpQQ/hgidyWqYv/uEjDqbh6r8sMdfkOJfWVQwoTFcSfwD2/Ezujp/A0M27lE6NNRroam4tql49iIRkSJ8j5Mqpc4aSg/1LGSCtGFO7lgwS9gOqERvjimyvLJqWq3dZ0cOYXDKpKLA0X7nDR9XyX2YWJS4KaXUr5+S2sxJzO7sAlTKSz6PH6BQ/b2JlcDCx+56VN8QMP+RCcbydnghzXKe6RgzxbAnDpW0JuxjjZ4MX8K34hI8qs2i0yxuU9+Mf/FjPgDApnz61m6zpE7ytZaS5gDZPTG3wIPktdrLMdemyyufsG9Lw++TxZ0idt/BkMk5EUrehRV+xT+AOX78k10N+lSt8JqDE3IeHtwqfFd0is91jzyBsgYPlipjXY6xSsJlNTYZ8aU/1mQMFLZvcMTTF703Kx6yRYTe1s9QIB3LdfeaNqDov7ouvZRgU5fNwWTcIt9sUTJn5/2mwjZpBmntggvmpmp5wC7dpNB6kBNb8jJrmRLMepO0ocqPbXE6JhTb8/yOhegEy3fJ1RNTeTZIEpBt4+sCZtc5TA3aJSYPZ51wEGmqMbiVCl1DnxLKmBc0O0JH97VCXcyhIKj4aOGsfQbqM3cyeIWuRNds3/do3Z8vOc9AQfcOnwFZU1H3df4iLKZ9pDyMVGCNqEeKew=="},{"id":"7c3e3c0b-5d1f-4d64-99be-668041c6cd9d","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"核心框架配置","description":"core-framework","prompt":"为GEO后端核心框架创建详细的配置文档。深入解释FastAPI应用实例的初始化过程,包括应用名称、版本管理和生命周期管理。详细说明CORS中间件配置、路由注册机制和健康检查端点。文档化配置管理系统的实现,包括环境变量读取、配置验证和默认值设置。解释数据库连接池配置、异步会话管理和连接超时设置。包含应用启动和关闭流程的详细说明,以及资源清理机制。提供配置最佳实践和常见问题解决方案。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,backend/app/database.py","gmt_create":"2026-04-22T18:57:02.316945+08:00","gmt_modified":"2026-04-22T19:03:21.69307+08:00","raw_data":"WikiEncrypted:luoNp8LvFa7zGThvIT9T4rhp6COPRJpm3tT/kftARqFq4dg1cG/8M10NcCrCelp/LC8SV6McSk0Sx9xEgJV/YmEmjfMmlukALh9v7ZKLxT8XDDYkBCrff2Ia9KfGFRdlfVmmQUGfhQARTeykGZh6O8/4GECBHUYLS0F6NXI7fSS3R+/I5c/HIjI7F17mVNpZDQZcc2HmM4zhdyIinOGyErSf3vIPcfVVobPB4D/wCUvMWxl+jpvktykHTIgH9ze7f4fTCC02xK5vRnt1RlMdAQ3d1Km7OOGjAga30OGvRdp9UtT48gdhzPQH5FEbfzn7K6TnuPzqQRf4GuS2kVTRSUFbSnmj5d5HqHmgx7D9iQYR/XxRRVbv+GeFwINvVa+UX9cnanYU19zazOGWG2rcdDk8jqu5MwAhVZsT28hykyuLfKeTf7xuM6Li86T1mZ18SROCJHe4LXYEaH94K6CHjZLCyEl10xBk02/CkW4aTW29TIgrponrmnrvV6bShQ+ZitR1TcivPsNN5t6TCaHMnlaLlOpznSGNpMyf4S51cRPxl2cwZrqJbrdFxehIoPrUyOvtRvtEsLhpo30456ihrInvbVXgJMwZIcDaKHSu0Bf7ma8y+UCWH61+VBIqW44KzA9zmKcXU9hiiwL+gjwiNcV7JDcgg43Un4qvjEzeJiBRBMGGzc8Oc05dWgRs1K6QUdS1kZTjI/JKiGS8zFYKz0mvQqLwc6/xe1/MDhMyU1QUXSqpcNNU6aFmY7te5kENN2aSPZqigqID+RwvIV8k8JETdmHaxJUzCSrNEpbpUukFuVQKz419athf4kMeQH2fKsLMZABn10WnnmY9HGGqBx+gpNOTU9AiSz1l4b0Ej8XoQcwIn1lqw49qdJ6+PRuuFBv6OcjxgJSMNSQzm4c/eyl7yv6J4vXceT7Ul+ySMAGRnSpDUehmOuw1DT4dV0n05Rcrx5gBjuztOAexxUhLwMUK/v+8qdn/0OcciISCZ/U1GhzhWFYiVKRBfNuNkuRjwmc4zg5Zc97TPRBXYs2q2e0/3cT+Dr7lqeGnXWL3X4iTjTygXMekhDQBjc0NbF6cdDOJcPAUnOg6jDkreBiEkTJ7hZg3J9ho2RYDaHuPvyMlkW4YWTpGRODtXIs4aLG0KFbNr6uOG31hOPZsgnHmoNwcPwRUO4G89Nkl2M6ZTMiNHWtsSwES+gLmCLPunm7R2zQNtdei+K3lzSg0bQgUvg==","layer_level":1},{"id":"bcaa04da-04e3-427f-ba01-847ad657e78a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Next.js应用配置","description":"nextjs-app-config","prompt":"创建Next.js 14应用配置的详细文档。说明App Router的页面组织结构,包括路由规则、嵌套路由和页面布局设计。文档化全局样式配置、字体系统和主题定制。解释Tailwind CSS的配置选项、自定义样式和响应式设计原则。说明TypeScript配置、类型定义和开发工具设置。包含性能优化配置、构建优化和生产环境部署设置。提供配置最佳实践和常见问题解决方案。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","progress_status":"completed","dependent_files":"frontend/app/layout.tsx,frontend/app/globals.css,frontend/next.config.mjs,frontend/tailwind.config.ts,frontend/tsconfig.json","gmt_create":"2026-04-22T18:57:04.216045+08:00","gmt_modified":"2026-04-22T19:04:47.361369+08:00","raw_data":"WikiEncrypted:MoQ9U2rERvJfHcC2U9f5yo5PrhAUeAY0OH9kgPk99cOGQSyTenUDM+krr5XcMxqj+FSA7CYnuq8hz8eS8Pvzc8yZuRRHbRPExvPpdrOEr8fRtUXkjnECv8NVvFPloo2fonxY9Q2vmL0x2O1UsV1O6L6tkraG28x1o504hsBitow5XMWkk8uSk+sDbyHo/y9/SBDWpcEOXVqeU4nwD/UU+7N90n5i5T89nz6b4M+31tkvffIuZRigZ+1+IJqlsqFgRt9PNrxL9ZUsD2D/Yvh8EJ0sCr9z7AI+D3z+JYM2kgFT/3ugS/EnEzwByGZk/e2EsOY4D+NkRBas836JX++o61ZH5GPQBXTHnVa8h5B1LAVlbA5zBuJHHY3V2XS4X1cTo9Hj76mg9Ha+jWvX2A9fv4vnscE6cVxnM+WjWnSfN8N7Vtla2YRDrNXZRAL50+PNfhUKpb48d0hKFyzf1Av1T4WBKgaYEo2znphEy99ViuG+oOFS6D5pVQ/w5yoPe5MpZCDk4aNsO/owrJkILcGc3+qHfld4Yd4HtYM6madWmmOvHIIuCy5CPGojBzKDcTTSPP6ZjuY1EC/RG3lBkYCQtQj889+80GZpaSbrqWjTmMI1DX1KLNXJkoI3dFk5Tx+w4TqiKICJ8q9KJhOX+mEVk+ECXqrc2Qz787D34zY5UlwsaA44ziBvWDZuwfPWmtelAq4KjqfWTFWYqdY6D0fUvetLh3/VEqH/o5Nh4HrlGvy/faZbU9FKOBZPkAy8c0J24rW5p2pKmRq6+2IicNTgufRROtiY87GKfbfmqpDYBEn3Dogv/Q3i5beVavuD1tJWhRsewhAZAUi1jWdiK3LyS0QI7dMFXVJw3cm2FnegeXA8CNlWnjUVSOY/OfLFqJJqYrfcj57f3nAU4a88w4h10+iFBLh0yZkX50llRxgUjV0fnjyEFUDoinC1xDA9ip9IOosTI+avZPhLTC0Yn4ZGnJi4NCD5cD88+KIdRUnVZJ5Sqf4ZcCCQamtYBT8NJ+PlByYxpqJpGtLyV9BuexYC86YnD3PJau0oXazcytuXMYh/TTaEo89ZzW4jpsqDM1G/gBUq7R+QDzLElNZfw3Ov0E0+Pvfm89W+v2iSsJ2JI2Yq7wrml7FiTN0KoP5KVEBCEzDLwebnJFqa7GBaghwADYcgoZ2VX2Xtin82a3oqlX2WNfur2DIr4YURiSmE8g8O","layer_level":1},{"id":"9e3d703f-f424-47f4-84df-b99873b93e5a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"项目介绍","description":"project-introduction","prompt":"为GEO项目创建详细的项目介绍内容。解释GEO平台作为智能学术查询与引用管理系统的核心使命和价值主张。详细描述项目解决的实际问题,包括传统学术研究中品牌引用检测的痛点、多平台数据整合的需求等。说明项目的目标用户群体和应用场景,如研究人员、市场分析师、品牌监测团队等。介绍项目的发展历程、设计理念和创新点。提供系统的功能概览,包括智能引用检测、多AI平台集成、定时查询调度等核心能力。面向初学者解释项目的基本概念和使用价值,为后续技术文档奠定基础。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,README.md","gmt_create":"2026-04-22T18:57:13.329466+08:00","gmt_modified":"2026-04-22T19:05:00.376007+08:00","raw_data":"WikiEncrypted:0MI1/XkBoMl0lTbK6t0CnyIiRc/FeBluVaO5vMjpi7GJDj6RYPJBK8z3pvJGG/q2Umz028dfdXdKirGdHRY2lrn0erk9nv1ZHCzuughhzuFHwcxdCPIpZdrZtQpPh6bsxkWiwYzSScq7WGo0sBeTvyoiisiPXNkFNbSjUGQOu0M9zOwZAcknYWqtf16nUcOV3lRfAFHfNSt77Nc0IUQGl1zM4BWFjitEsa6cq/jjGIh7XC2gcTvm2eWRaWDDr5n6IcJZtD0ODJYzhH9IJVk4uIXlKksbQcuIrmEWEkZBxeh+DAIp0tmgXr52zuL9uRxapFuSlOq3BlU5N3I+Iu8Fg/rBAnNcvKEwSk/71gIbFlwaxLvik5gposBrfcD4U1+MJLRTPhgg/HJwljnpTC13NERk70aJg2/SCvFZcO+86xWuLwvNjWRxc2K8yOeJggfWG6S/Dt0dGaFl5F44u6XDbQV0GKiDfNOzo5CtzO7CrkSRJ+zErGQOEEoF6UhVmmpA6ONf2YDr/z3Z5bIP5z605qNZZWUDPVLjU5elINOMi4fsEw3OYaerNp6aoSHA1eXnOJoJIMsU0KM3eGAO9QNhHE2PlkwXulCEX5l1tkohbwthcv94cBVsn64CtaMMgjrgUkflNYnfEM1djmP2iJFEG/MjNMntZCrVRGXdjjqR4Q+lRe3ELhXuHjqeU5RS+KdYLASsYBDzti2T8foSfBxxXcpMIz/lS8+Qx3pTLW3ktH5AaEtSdclWCF2HLc1/03O/gdv070KOck/8TXbyZsJ6g3fzThY7xASttVsW1IITTaX9XE52YkNOe7KOrjJwkSbUgOU1Rv3Aa7x3VJ/ac9nDL4AgS+TlYNxfYBlGkbesL+sqDgWrL268y38MyK0DRqEQVjCxV9+7aAkxLvaUXVMYIwxqAM9Id66zRb0pJB3uwgpOAIRzOCskNEghjp17p4BK3lgehkRcM9RAGb7WqgeNfl/+ox2b25Pj+nvbWN3XghNZwNzoTW+kBZxXhOTRvIyAne7IPRpmtD1XD6ZBx/C6ucQ7kTUL/7LqFXE66g3Zey3hiaiQihueSMCFVer6F+BIMSBpV+9cmAczdqYvXRnKIjQg15zwVGz7mKE4D7caiDjkAQeMUSqziw+i/S26Ont/JBHIsLpYISQJErTAl2rGwC+7ADw+H6jg0rn+nE5s5u9fxUPMsWodcWi5oGIFRRTyGeIZYSTNveEwN8h0LGwXhUlHR6RxBAIpbiwKVUcOFOKc7mojhJEN36mXsQdRyCUjV3YdNzj2Tw5tG4exPzStsjDxSn98XK42QisGde126iI=","layer_level":1},{"id":"a06436ee-1678-4a51-bbf8-b0d0ac3456b9","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库架构","description":"database-architecture","prompt":"创建GEO项目数据库架构文档。详细说明基于PostgreSQL的异步数据库连接配置,包括SQLAlchemy异步引擎设置、连接池管理和会话生命周期。文档化数据库连接字符串配置、环境变量管理和安全考虑。解释异步数据库操作的优势、性能特点和最佳实践。包含数据库连接监控、错误处理和故障恢复机制。提供生产环境配置建议和性能调优指南。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","progress_status":"completed","dependent_files":"backend/app/database.py,backend/app/config.py,backend/alembic.ini","gmt_create":"2026-04-22T18:57:14.160162+08:00","gmt_modified":"2026-04-22T19:05:13.623934+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkJxdCaPVm76qYvPs0DmFrBYr++cWSoBpsZCop64XjnmZv6vHv8URIJAqohtlaw1HFotKc3mK0aD3tk5jmFWmTjGEd9iSTEcB45Yccg7p5eggZzqexWRLP1afxRQPau2t5uy1dZIlExyu+lyiNQI9/hXf1UppgfCjo4u6akBIZtYhzgcUSoYY4jCjv0naBAT/PyevZQctOpKPIBwMdeB86h71UT0hKB1hXxbyQoljBYZmATJaRjmlQzZf/Ka1gnDj1s1WVsGMpSoA7jyNRPH+Ra6hR+5N8Ba5vkjxM/HcRFq282Jnr/TnidF4MF5HpD5Piye73QZ3zAvIbu8+iOSvpQee/FTzkrUQBy0xOA5lsfFOy5OFOKtQh0mHybuNqe6H5squ2Tge+K4+RKXbDCt0wptrSV+BVQ+OkAJJEtLNRpJElsQ5bw1UU6CuzbgnnEYrMXB5TMBI5N2/J6hmlqt978t04N3zVI9JnnFKK0H2og6TVu1Hrxq/xEB8RFWTf/WNN1p4Akee5r1uOuUry6hsO2yQUTlmHq74QnJz4o4YJodWkhwAmcyzPIlMeSFg/Kr/EvsQJN4UprhudCTvNitnPaBesVkucYDYQiVAhxyNSAqCzZUYXbyuLD4r5DKxKzvHjkhRugm73yBM7wzbxB2lABMiGM9p90FASIxS0SfzIl4qrFbO/oQGRIFaYfUCnQF8h0YDi40UX4/LVmnlT/L8y/d+hU00P5j5PI0qOyoRDqsfQZFaze+qtibkMnJ//iy0Awl0wqQ47SxaB0jhTc07lPFBLSHFSoVUaKDs1DPGiwKjpWZRzAw7rbv9NFuV+irKc0l8qDNCaK6Rk0rRd0ukFuszcaE9n92URbvv0Fk8XTHLr8sFAh/xMm63r5hUAuqEYN6z/Si5Isq52UmJ1/TvnLYIUK58JHTuDsVn3MKJ2fTgUw/U3g+N61WpDIgGvaHO75crgWZbS9qQyDoSSj4wNdxWR+wtmKjwZdRK44kWRBS1QebMTLNYDBgHD5hPnmOa5W/Rx4Y0QBw6UFjCy/GOmDI=","layer_level":1},{"id":"7fea5a24-e6de-4003-bc70-9dae6d8fdb25","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"适配器架构设计","description":"adapter-architecture","prompt":"创建适配器架构设计的详细文档。详细解释BasePlatformAdapter抽象基类的设计理念和实现细节,包括平台名称、平台URL等核心属性的定义。说明抽象方法query()的设计目的和参数规范,以及close()方法的资源清理机制。文档化适配器模式在AI平台集成中的应用价值,包括如何通过统一接口实现不同平台的无缝切换。提供适配器扩展的最佳实践和代码示例,帮助开发者理解如何为新平台创建适配器。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py","gmt_create":"2026-04-22T18:57:14.592407+08:00","gmt_modified":"2026-04-22T19:06:14.01609+08:00","raw_data":"WikiEncrypted:mEeeU1uNqYKn4jkG2zPtuGBVTFJMKL8+aALSFPkyoEYifQL2Z+klmgmPGyzF3YlP0xw/C/hG8jzgXcVjqaWbA8lOQYPPvd4qFK8fszqAYs/fYEHXvWBVaOTbFhjNiT5k+li1MqVRx7SiaRze/N6NV4j39o5dfNAouxnCXgLyBZdG5QXj6JAfhJ1mTHsYQFDmrIU+nOtrQvRh3bruUOURVd64c13kwbBISJKHVwByRrfqWLRTsCLXPYfsgZF4rkL+Iz9x27Nl0VXvNcIIoMXj9B7hg2PPcQlmup4U8y2LhUHmKrdiKpW1t+XZ8rpO2aPKpzr47rn+3n2axWoQIDjWKlHAwi5AhxgPysB/i5EGv0pvgo/mNNIfsZlmSYgXASM6bgCzH5W4O4oJVqOi+gaLuI5+i7N8/+s+FKb63H9ZNvwClw5jXJe2Xm1YUwVGLG8KX5beKRTmBgnyDPmOW17/OXwsWMWQSQKrgpiv+2C7VQqI8X/agBVWawLJAc8VloY281S3ZH5LTa/6ajeGUVXiwpWSD/YWzo9sxLdws1ZXCInzLYy5vX7YflgBOlw+pn6Z901TBktq5jxrG3CFTbRLGxaeG1aJ06sLEFoPzLSXIIiEIuAROC6lPr6XpYAKESgWGOG0GdM3BinxdkriGn21ZZjENIJ436aZjsOiE5M20/kJAnjWIBPEJ/sv3nsi7u5iLfYFvkus4GfnKXJyto9LWiTgqrwHoEUQy4+pnVW+ce//iLlM/t0ZknimuBfzgYSWx/jPc8o9ZU5OIserDAYGaE4sDZIDQas1jOq8HGN/q4wJR7sW7Fw1jKyl4suQZE6QSfYx6molnJ1cSVKcsGrf7AHDKM5x+uGRmLWXqMMUZXXtbbCw0mwqfxAUPiRLUdVyzot8dh/NIWX6B1KABd/kKs+L+vVuCmMen1XVfP72Uy91fYOkBj/xPkA6GYrempnrB6zh6INdvGw5dEKlvNARMnZZLCA64Xw4h2TBjbkIjsBawvJtT+wEGkfkPk5z99jbaaGS65e/JDF/g5WNnKSX0B1Xo+frM1AFwnKR4dIJXZ8=","layer_level":1},{"id":"78288302-33bd-44f7-8b29-24f516c8b6bb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"调度器设计","description":"scheduler-design","prompt":"创建调度器设计的详细文档。解释基于APScheduler的AsyncIOScheduler架构选择和配置,包括调度器初始化、触发器设置和任务注册机制。详细说明调度器的核心组件,包括QueryScheduler类的设计模式、事件循环管理和异步任务包装。文档化调度器的启动和关闭流程,包括资源清理和优雅停机机制。提供调度器配置参数、性能调优选项和扩展方法。包含实际代码示例展示调度器的使用模式和最佳实践。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:25.383156+08:00","gmt_modified":"2026-04-23T20:33:30.132403+08:00","raw_data":"WikiEncrypted:z5m818jdZZHs9QqQTrTafQ5BuN3hUq8ojqzL8SUBUvazzYVUu4EVEqQ8I56QCaxYSTvxoxfSrvjJk5zRU5X7dcnw4Xa3OBhn3OLehoT3E+tyMxhlJSbJpOfp1afGCLyH7k587Ud4I355IvboUvSoBViL1WL1yQq+6Tus1CsKPq1yHjNiWT35OfV9g7bRu5xE+1nSxjPu58jZpFKuN1x9oqF5OJmckHxf5sVFqKlGPU2yyeGdpzKRagbQGUkBdw72yxzSyevTXJ4y+UPCQLh2FLZ8RgYP0OD705z2xIGb7KSeQocLcW5FoxR79ySiibc+AmzE0OBKZqbcm/aw8K5lAK1GP31LdhjrndMTmXrsf9CYBNRIir1QOJsuCh6zPtpsvQVmrX7DpqXiWsaqnK2GVOkKPtnYAJnGsEQhaoX24/64eSYeSnJ7KIsQxP0MHUrRG85VVGF2ADUGh6L8qzexe7uE+lnaqgC8HBQ7CnQ3Ugnj5hcO7vnwQl67NHMOQ5yaL1SpfURVWAx3jjUBU4xjHfmUNcBC2VM6ie9C6Ulelai8Pg0+gFL0A+pfN/Mkzzh05wcgnmFbWfjabZ4Ofv/w+UlG5qhMsEJQAgag4tXHgP/86pheTsfyefYhWEkow983vJf6mYl4lgRaFHeOZ/JBTmM0sxmg1PMZ8wgClMSC0a9SKcsAyWOh0yMuBn/Ckhx4HqGoPAP1rx/k9TkBiHFEoEAXeTNoeg/Wn7tVimdgZvAjW79z7lbcRV1cvlKMSjhRyO2s6n6N3Z6xTlKtLrqHBbXZcrjNQqJVgW91Xk78+a1haDNngswufhJkTJcH8hp3hSUCJeU/Cpx3RYRRf7E3bGmj4sV/+yXAybUvCOhs1s89mYVFThdpDifMbvN5C8a9xrjKJNfjzijlVZwx+cGy5aj+ZQFSDCRCBHvCCIBd76w8uxi+VR8VhbsIryP2KUNpudqIY4V56Jx3DB+dznNJMasPFZZ2ZttlKIAV7oqWrreoweIqeEIugrIM4TdE4EWmokDP5wr0tBdyerPnkaCgJLQj3X2K/xjY6ony3F4svfG1pk2jd5JwTLnudwS4dnGY/1b//vEDGI668cQtR5fW7+APXXb8qjOLlzM4Enze4mw=","layer_level":1},{"id":"b027f234-4ac5-4d6d-9b38-afc8054325f5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"单元测试","description":"unit-testing","prompt":"创建GEO项目单元测试的详细文档。说明各个模块的单元测试实现,包括认证模块测试、引用引擎测试、查询处理测试和引用数据测试的具体用例设计。文档化测试夹具的使用方法,包括mock_user、auth_token、auth_headers等测试辅助对象的创建和配置。详细说明测试断言的编写方法和测试覆盖率要求。提供具体的测试代码示例,展示如何测试异步函数、依赖注入和错误处理。包含测试数据准备和清理的最佳实践。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","progress_status":"completed","dependent_files":"tests/test_auth.py,tests/test_citation_engine.py,tests/test_citations.py,tests/test_queries.py","gmt_create":"2026-04-22T18:57:25.616384+08:00","gmt_modified":"2026-04-22T19:06:55.090058+08:00","raw_data":"WikiEncrypted:oQ7VNoYBl3ApU4O5/TGa/YEO9ObmRNw6knddpSF6M+qfBokxpt9FAn5Oh9wXkjVweu6TpLk0XawcRFRcQ09Zi+YnQyN8+4Ep9fANKzHyAxzcnhkI4VZF35j3DwTbhekUFTKQ+71fms4SP6LGrVw+8IP/eqJC2TH96LJR1oxckQk//yfvKqFHsMLgziXy6zrXuQO8PIu5U/WbkKUkJHWSkLkoTtPteU+WKljSMapCS60e0RUDWZEPuFD2uupr2PJxT8AoOXx358C9XEj8tQ+OwHpsBiR7NdmO0D3GmcgVUcuU7WWxnToWu1UM1d/t4u+x7bIQvHQIDjLWR40nTrvBZJBSSiui0he3T03jLkIB7r9kxCpm9mFUx0fkmUSWp7FRfs7MfJkuoQYVU0YHf6/FF6g/PoQ8ieyqr4YaNjM3kk8GirHkmKjfdQt9YmQtuzMWnzUQ6COtN+BG3STyOvO+12YQAYi5LWe7u7oP4D7TJRReg7FeLDQ60Y8KEoKBJKM051F7pgHlorthWz42brF5tF7oa0tjB4AtWaEwXdCvH278kzwHNEW9E5zeERzX3hlHYL+mKpTbemJlfuHuRugCRy4EKFRP0RYiIUecBK82Pi4Vi9MGjB7cQxIEutHQ/3D0JNLGwEo5TCsk4W3isoF+mJDFy6/IDwgW/+5FIo7V/G18dTg9YbFRwMecdvBfJU5QZV4R993bdx+kH6qB5IoJrA0AzBOCn99YQ/xgAd3w/82Z5vR8syeNZjHYmcx8P/XrYDk4UZTwaacEHfn7tcq+tL5qJDbxdY95wjaWRo9giFE8woDfoLWstvKA1/q+YOyDsIHC/uHjNP1L0ELPZ9ssFuHcwLVrqDwlcblya4+oXlPEOH2ar22uXNRmFyd8Mf8MmEWVZklodBHSKiGUlj8eSWqtR+Cw5Am1gmeUcOxqan5YwzpyXet6g5ll12dnu6ItLby6qm+kjET3rsjaJag7UBlMXWV9xn9Vj4QDK8USPTTWkRUEAj4WH9QqECQzUtYJ6+GsIE7LGx/5tzApMdX3BThIiG8C2k5ry3z310nAMX/pTSrGFGjy8tWFf+KH95sJ6aG4CDyxSPHT/3ivhXAnKDesNYTVgSIKNmAUcj5hRjTfJeGyljB7NEs6Gxz0tf5k+GQLwvRX6PxSnMGkm+q0yx0MNDRBYJNlPCFKUR74ZAU=","layer_level":1},{"id":"940e5918-1689-4001-a284-44f2de75b8ee","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证接口","description":"authentication-api","prompt":"创建认证系统的完整API文档。详细记录用户注册接口(/api/v1/auth/register)的请求参数、响应格式和错误处理。说明用户登录接口(/api/v1/auth/login)的JWT令牌生成机制、认证流程和安全考虑。文档化用户信息接口(/api/v1/auth/me)的权限验证和当前用户获取功能。包含完整的请求示例、响应示例、状态码说明和常见错误处理。提供认证中间件的使用指南和最佳实践。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","progress_status":"completed","dependent_files":"backend/app/api/auth.py,backend/app/schemas/auth.py,backend/app/services/auth.py","gmt_create":"2026-04-22T18:57:37.836287+08:00","gmt_modified":"2026-04-22T19:07:12.356456+08:00","raw_data":"WikiEncrypted:uxAckj1IXK2TQH//kEdeBPmScopsydAsQUjZb8Fs6jI7ezX3WnM5wMv74LMiw55tL2+YKxETbMgwkBQYqIg1VTja5IjBYqljlAzD5l6SrkKU835vZQoOKlYgIFEEXj5PMURu9+2Om7SDVgjbSQ05vLa2aVIBV6PiVswRGc5EGTGtYnV+DJs4BxHzYpH0Ac7KkyHUCGgH6w5QDaOxWt6c5gftFmsRwr8WVKANmqlNU9uhDjmWzjTtSqZ39EVbLd++OjVbpLbTtijQ6gOF0KBBS4B0N5k+Xm2/gDv+HNK9kZ0BphZE1Si3NfV0+cu27HLJ2XV9w357rte4pplU0wYG5oC6cuO7eBFxQdCR6e+ejXIvKGahQOce8d/jWexjfdWnUzvQ18PU4+bUZmiP+YD1dJVBFgxggbCIHG8VFTQBqMaYwc3NLWogjXnczII+Z3sLLneLkVAQEdQ381GeRKdaD4PrtAWp1Ss2QpGHWUKDdaNSLcfm5NXEe6GeECxXH96p6BvyegD3twPfZmY9WKG8YOhXqbpzae/+DXnUTfldYKnMfbonSav0nUBYt8JA0L3oceaNs03211fvlSgE8L9vtUDtNF5lHkhOLMLbu000pe/VWc8WVQRbCKd8KPd4TUxMkB61vQNIcvlRKLMJLNSnE1VftRTpdEpWKhm5qkLfOfikgsp2qp1iSw5Idpu/TLQPIGN/sYpTJ1eACeXt/A3qrlITHFV8by4utTXDT1gRQQ7j7n51fQHHEIbpU+6CRhSBBQfa5IlWAqkarenBmr5RY74jeX7tlhDhvFojQGHYyMaDsZO8G/H93/20YG/li4iihHLIYmsN+2YRP/KWCNaopBGp7tRyZi//RKVXdHGteWxP7vse7URwPhfmHDUB6dMExCT5PwgsYoDwD32k19Eauv4c6OogAMMUN3I9rhSo3V0cde7/xSOhJ34SUY3w9VpPAu1I4zTqhY649YmBnNEjtGLZGTnEJWSdneSPsudvl1HJKg6faq1dMy0dVkMqbHaqMCooFDhiYVS1AM1cG07y9rQisvQP8Ic3NTPAA7BhH0nrPnLc615Jg+XEAjs3brkNXEVZlxNvX5ZqMCoMqsiZrA==","layer_level":1},{"id":"6406f42a-e10b-4a2b-84a5-0a21c1c759ea","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"代码规范","description":"code-standards","prompt":"创建GEO项目的代码规范文档。详细说明Python代码风格指南,包括PEP8标准、命名约定、导入顺序和注释规范。文档化TypeScript/JavaScript代码规范,包括类型定义、接口设计、模块组织和错误处理模式。说明前后端代码风格差异和一致性要求。提供具体的代码示例展示正确和错误的编码方式。包含自动化代码检查工具的配置和使用方法。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","progress_status":"completed","dependent_files":"backend/requirements.txt,frontend/tsconfig.json,frontend/.eslintrc.json,backend/app/__init__.py","gmt_create":"2026-04-22T18:57:39.373374+08:00","gmt_modified":"2026-04-22T19:07:51.274139+08:00","raw_data":"WikiEncrypted:Gw00+yNdsAXvNpUHE0sZ2+QbHW33I6XBnIRt1QjI/FW/5OIgpgiMvU/f+bhXrxoZK5Mgo6YrGuAKhtZ2BPutU1EdQeDFUnQQxxqSupe1WUkFgEECvCkbZOAHimRWBeUutq2qKCfVhu1+US1y8n87OZXUUvVSAksZOa8lbb2AHyiKTMdzzPThS0D+8uOalkBg1mvJCS9fqVoZzY5BYYpuH5eZJBglHbA4uMbdFVTSKVFfHaJ8nlm6uYjaY0sJCSg+dhEAIiMfOTXP5Bh59kxWfLSdZU6b8oPvLV0btsiS22/oEJZI4rWjJ0YTxfQ4jRv348P+GQ6oi1pvwveiJyOxLq8QcVKSiDxO55Ovd76PhOgpOp2WJcUsKoKBoxs817utm+Ld0htpPBS3V90Rw+suMSPCU0mCa80FTrBNn6PnXemH7lH1ozQIu3Y/AGNYBN93acBxtiZ09sGFh2sO9mbbCU0iRuNe9nwWa4MsA5rJMLGdRbyv6jk03+sAvuKwZHXyTWxqeXvMatOUKXzTNfmhXsE+Bexe1vaukG22SWhsXu7FhIaH4Rt7CdpMW0jjbZOf4CwKY36ucVBRwft6ymuED4ihzikPz7pJ5IEuxLGtCyt5QDqT7kbv5ITx4NM/Q2IMMTRZf9bAZyN64PV2TJVCNK11yU+cE7y8HFBNFSzPfDBGFmxijKjTL9MvlElogPp0+qckxGclnip/IOFc6/WAbPNK0qXq98Jq5DsZwLsx4//8yOyRyaQGmOVaOWxb3Aum4RIf933X/hzoTFpV2uSLSznRyCwLpKqjp2zMS7lCj9aDhWLcx5J9NxXfdxFVxBsapMeDDl5xR5nfTFJcOFylsdPxEdxf5J8ULB77F3OmE8Hff/40adNMxJHMyBmju99HNnMZkGLjC68HEPNMZ/6T0+m/Sq1yHOrakYMiw6vnQvmLW4cBIhsTFbhbgpkazGFTk8xsKH3pGySrLXL4xmadfs/g2X/lRrLbSonWaQehTqHYrhz4HIxrTUDn4kdxaPPDhH4fHdEu/69Dri0DSzmSF2m8W3hh1gbAbUO/mbHob1eJg0yKGzyh8AmvUlwXIRGrOwQA5dUZNPSo+oCcv1qlrQ==","layer_level":1},{"id":"e8ec6ac6-ad1a-4332-a7be-727b47d71233","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Docker容器化部署","description":"docker-containerization","prompt":"创建GEO项目Docker容器化部署的详细文档。说明Docker Compose配置文件的结构和各个服务的配置参数,包括数据库(PostgreSQL)、Redis缓存、后端(FastAPI)和前端(Next.js)服务的容器设置。详细解释容器间的依赖关系、网络配置和数据卷挂载。文档化Dockerfile的构建过程,包括多阶段构建策略、依赖安装和运行时配置。提供完整的容器编排流程,从镜像构建到服务启动的完整步骤。包含环境变量配置、健康检查设置和故障排查方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,.env","gmt_create":"2026-04-22T18:57:40.354835+08:00","gmt_modified":"2026-04-22T19:08:34.084609+08:00","raw_data":"WikiEncrypted:h7ADvj4WLJHyulzCl+z7kNgZWY+r5P000yRKX1NQnlv1Xv3Dqgu5Ve8V72HxPVQrbKK8WU/ipQ1PAqV6SDrNgrc1Neea6KoTKr95imYAh3dYgIt/lZ1sndBbQCFqOF87dQsUIEKQgwrsicAeQ0zdudUWh6EW2nyIF0NGa50xffbgEr1mm/MThBZjOua+YnCRogCbgtirEO/6HGlC+I33w/bfFI+rREYKdumqUEia0kUP0pWSpwWjOQp06I7cUoSrx/LuJJ4in5YsZetdjzxdbA3ZvGMjeyI/VVF6UC/QUOgE2csP9z42v6XdOOngM/coBHI3DiUrroBGTPa6BVxJdngItCJ9XcNvXPbo0xMAkAoUKnNPA72B2pRuk4F1sTiOaSCQ1jaMiCTFvbj7+VleaodRFLDFsYa8f1w2FkiW7cEBhFpFgB7Qfru+Yi11rpkjnM2def+Sqq2PSHQ+Ji83jPoQXFl935rDQbNUy28wOIE3BdWN5jjM3nyoXcqKjPVjLf3cxGvg/sbdWk1FYPMIsbK/DUWayyTHt6L/fYkDQYjY5h0H6Q0jBxlhNQ34GG8kEcvrZ6Dy/jtCtE149pi/ToeMbpPq21c5KUhs9OHcEHgMjxWMaEVjQXMjFCpKyJIPfC984tfoZhAHi9WupzyEi37/igcgVJnvIdtadpX7uRxW2JCdfoHn1H87nGQj4eAeI3kMhtJ3EIPd/D6STxUcgtyLdTIZu9kgvnBIN4OyZeI1ygNZfawwQMmbDxHZ1pPcyZDHFlz1HZ0NFX+7VnN2b25TJP2hxMCZ/5OdYeSLozIbM/azA8QMHofESSdxDX9ZDdhvENDlngxUBmxM8+yCAWHENGYqWDL0gZMMDwe89n48Xy9qnKNLX0ROfG4FAtoXsEgLlPQM3AWFETnzr7Kvuma+8sY1iaMVIXJ/MWoy1zLwuY/oOZhVqGLX+DOEupKhk1oQmiqzciCeV8my5Q6LQeriSBww4jA3r6VQMPzBVzKJYz+TLizB6Esf//9+ilsgUVUc6GjD41Ml4fb1GZO3PzxGWrcX1RUE6RKllUBVNffxzE2WCirEX4e4YprntsHu6SAb9TLIInCx7aZnlVnaDQE5BCiHLjIQJnsHHJzlBm+8jtzE4zi7ljHLfbJwhtZ9W6S9KGUqjjNryjTVnVyYQlumOT8HCAkz3fSM6MpXwQr1qz/gHyDrQanmM1O9B/0ox5O2NWcOm5qtsteiyxwKACdyxrsUx0X9BaU8xygDL75XcTfcaOTcICRwaRZF3/UQW+zhbJo9LnHxq30JzTbxU7wEdjpWZQHZ+tu5BMrIqi4=","layer_level":1},{"id":"a91fff3d-ec5e-43df-8176-22f0084109ef","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"功能扩展","description":"feature-extension","prompt":"创建GEO项目功能扩展的详细文档。说明如何新增API接口,包括后端路由添加、数据模型扩展和业务逻辑实现的具体步骤。详细介绍前端页面扩展方法,包括Next.js页面路由添加、组件开发和状态管理集成。文档化引用检测引擎的扩展机制,包括新品牌匹配策略添加和竞争品牌识别算法的实现。提供UI组件库的扩展指南,包括新组件开发、样式定制和响应式设计。包含完整的代码示例和最佳实践建议。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","progress_status":"completed","dependent_files":"backend/app/api/,frontend/app/(dashboard)/,backend/app/workers/citation_engine.py,frontend/components/ui/","gmt_create":"2026-04-22T18:57:48.684421+08:00","gmt_modified":"2026-04-22T19:08:25.140739+08:00","raw_data":"WikiEncrypted:5RlNBsIi2/3o8ATlHuzaYD9/6k0SjLB2nW/cTN9Sp7ydYLe7mauzXPQFm5pYVoY1D1K/aULghB4g32vyxSUIsHV6NsxwYA/5+FQ8w/4xsQc3urcx9OEKeSC0hGU52WXucdAGjiEq/f4wJ2c9FdJEeALD6eX7MltcooFsxAVRWIKzHsMdBiy0RQN6s7vv4sb8vpV3b1ET27D9QlTUiTPU7RgtJLMui8iYiwJIirfL1TgdGRSx0Rr3tY/JvS3/6/L6VU/69BKglW8DnLwDkWKuthI/2sfWQa+lb+uTuixXL/VbltWQnzwjMVYghhTizEEC0xTpFGcDY/ajvLcjy5+wSleNEr9AFy/ytJKkpqEO8Zt5qyVJ4eANJMSXYcoKrZEskjVpnrPEHGdOzaEaCqcl2sQYkXde8LWM29fWmwlMjwJzucGwhudoQLXgkIwJnD+jb1r2SdjjafTI76MM53AnSfD4aj8K26yrOkVtoD6nWG1A1fG6F22pPBhJdezNJCYuKBaSDxJDES5486L5Gm5RvjYDq4r6RZ5CheGPgxl29XjCimgWuxXKVX0jPLUawteo/Vo5D7AHzucx2dX4mKr4rSSSHpD4HGdbwnxZ717DkRG01vTOnue6gSQ7pceMjSZ6TnB7dvtwwarHBKQMKwJXrpqxc83aZQjW4sRTAJs2Gc9+11c7qT9fQnGK54JJjEARaQZVaDmTpKmme4SKKxCB7V8yUqR+D+swVuSjIpYdL1m7THJtbWSSLaKkWmYiom1C6qb4GIgO4CT/IiFSyQ0Sz8MUIJi/dK0l/vVmpp5p3IF5K1m6NHDX94yEPWEHsWIS8eC2B74AyX6PG1fWSt7HpiBAzq8nu8n+IrXPqDege5sXbjfNrbvkRot94AvLF2aqMbteOUGOZxMLASQYyfRQBlaEEFMiKEVNTRSaHqiS8mS3pG6XLcV7TkWJIyMzhcT93hKXrSB2+jLa/rrxxrZwfp6lddgEcV+XZzQU3KsJf8blNUd+UkA4TcwFugu0um1Kr6Hro8EHAR34+FGMbPskEPPX2yd42YXx6qfmcFrI1xvHIQfnc7QuxZwO6GHR0G5LiPtuV4ZSxklXCwgnGWy1lpC13xANNvM1UKqAuhpuV2qU+xayK5IQv7kQaDOJpnMzFj/dSxtRgL2Xm20nH4BA2lhBCQMqeM5OxJ5vzwVlgVMZxDbhwrRaDU6cudgNfRJDFh2lGQqE2flEkvSF7g87Hc5H3qDQxUv56qpdOPJcgugKJtT3Jz4dNt3+eojvEwrTUc7d2Kq4KDTFUa5jDr5uo9PZhNR2TDJazpNIdl1x/64=","layer_level":1},{"id":"e3ae8925-4862-4280-b85a-0b376841b15e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"快速开始","description":"getting-started","prompt":"创建GEO项目的快速开始指南。提供详细的环境要求、依赖安装步骤和本地开发环境配置说明。包含Docker容器化部署的完整流程,从环境准备到应用启动的每一步操作。提供基本的使用示例,包括用户注册登录、创建查询任务、查看引用数据等核心功能演示。说明开发环境的调试方法和常见问题解决方案。确保新开发者能够在最短时间内成功运行项目并理解基本使用流程。","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json,.env.example","gmt_create":"2026-04-22T18:56:47.081987+08:00","gmt_modified":"2026-04-22T18:58:54.237875+08:00","raw_data":"WikiEncrypted:qfgbutC7oyxR6nMxrwk1ODnNMBEQ3/sG78fQT1yXWju83LC7H/jAM8CEAvWT8huE5OClmQiIfNYNxHQ9s7RRS/GGSwI5DTgXTPiPdxvdU9tU52Y4wj4FfVrOtqmH0nMPa+EBKH1Wo4HibSewimTkeCuJVAAjyygiPePcftR4ud09LKmopy1NSgZrtHMoDFDwUOcNJQad4OVgxMnOi6B6z6s2Oh2aPWNJX5EvE5xGkLAc6XvhE2T7MU40VJ4lUOoKlCNZNdI06grEqwyizBqt13Hg20wonqeQ1uPs49UbF84IJecH3DmE6KW3oqmqvQY6tztk79eE1bKZmBtQKXz8WhEMWZwALTsVk+hkk4dH/fcDoLteR1iuO4FaxDwAOaD71KF79AaYxDZiM/8RER9YsajjGSI+sfpJALuiQbqqfKbYFSgliiUcf4gTM20Ey5rtfBkcvBY6yOBPpqdKg7/ls7jdggNEWDJfN+DPVzV4SGAYRD4g/kDzPa5vaNZ6USRa7hVIR0SJufX0DGSdzX5BMh5DQEEyd9svxV+bs4KPZphBIeqAOzvo6zyF9l9LjPPdEook/uTIBHjGgx+8Ck1NQEeNOs61Zqr5EfISope1Au8dYCrzwpr02s4XAb/6bYsMSkfVqETlSSUkipDodGoLJU8QiYr5Pjv63Bb9Qb7SZ+i7NrGp6UJNVT0etywEMKSQn+73I8e9AYrAxlN5ST6K5b3W7cOPzFQMCVRfzvdd/FbuN30u7JXlFCnm6Ee8LDHW6nteOxBP1D6JxbrQirCQE0cSuk+d8OR5tR/DJiRDcjbsG38KVBEqWnIek8KlMGxEt6N3oq2ceUCCLe4jVURPc/2G/6gNiyVq0dPPAVwjaNKNwtiyaDhhBu4T21k9NUfhdQNz9DJWD0wXuaZc89RoqLNlCHJ6TtxEHJ/Sv4cgvm3QUierIBIqUawkCMEDn3ZEo7L2fUS4fMlzfpHSgTvxB43ta+H1m6syFUmAyh1yqfXVxKZY0f4JtmBbQpNzpT+aRHMKKQ9UVvtjvNcpupzO5aNkyclJVWis66DMtfA1H4am2gseXSfgHHtXiLfOnGoELSM1fLS+T9oPt48v+RPafJQpahtNeKtZc4dbTcsc4qlS1krenNSBbkKac4Zsosjv8xHuD1aqYvAS476XT3gjLfV7YUCF/+i3PiovD9NGzhA="},{"id":"c19260e2-5163-43d4-b35a-b48aae995f4a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证系统","description":"authentication-system","prompt":"为GEO认证系统创建全面的实现文档。详细解释用户模型设计,包括字段定义、数据类型和约束条件。文档化JWT令牌生成和验证机制,包括令牌签名算法、过期时间和刷新策略。说明用户注册流程,包括密码加密、邮箱验证和用户激活。解释登录认证过程,包括凭据验证、会话管理和权限分配。详细描述依赖注入系统在认证中的应用,包括当前用户获取和权限检查。包含安全最佳实践、令牌存储策略和会话管理。提供认证错误处理和调试指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":1,"progress_status":"completed","dependent_files":"backend/app/schemas/auth.py,backend/app/services/auth.py,backend/app/api/auth.py,frontend/app/(auth)/forgot-password/page.tsx,frontend/app/(auth)/reset-password/page.tsx,frontend/app/(auth)/verify-email/page.tsx,frontend/app/(dashboard)/dashboard/settings/page.tsx,backend/app/api/deps.py,backend/app/models/user.py","gmt_create":"2026-04-22T18:57:02.317252+08:00","gmt_modified":"2026-04-24T11:02:17.638164+08:00","raw_data":"WikiEncrypted:1O68LCvyq1zgacF3KZk5YThbR7ok3g75/gwtsJvdh2o83INCVjstQiF01tda6hFb+2JTqgZSefMRniabd6NWxIcxLGQkPzKVW/Hd8nBmAPUj7rQun7N62bOjGs7Vdy4RhltwZryBPaspbuAyl910fhwCIzZMGRfD+PXCWNv/v434hWViOvWnjpYaMrt2sX9Ljy71CYMLz0NLL55ClE3+kRm2WBxbzfWvpabmDbKCJIjHUouLtLTqa8nO2ZD/mpn8P/USYy3J+ucCQEsu8jbkFecDJgSCRkNzfeLi54eh7hIPt3cwY3k1GwBPcK28HnOkNGaLuFV5qSbDgUwDBoJ1ZTehKeXMMxAuPFJ+1q+Cushre7O1bOmgO+I80GEecYAmWGgpx7U8Xu3tI2XaqjSkfRQHdUEezEWtGlEdBOV5pTVVkz/k7SvMCf0IQSaeAV4CB0uPNlyH37JexzmbUl6SbJQzlmX5BcDo56/DmhFUZ+iz591eZevVGaIdCDU9scQfmskMZZfkf9d+T9heLb3IonhkwGtoofl1NWkyMZ4LRfpoWpOQVz5rwZczDy6DzPtcmJMGgjGoJF5qad8II9wEjnSfCikdIKBXQM/KBIZKZDvEsRH7Kf28A8nCpNpf9eKymJ9xUlUDXB7chWBw+J9WK5EQplTeI52vg2TWVsMNSe/gBLV0GDzzFNuAIAOAh+BEGM65LlZrL89p9j3rI7YORJ+qtC/f7HdtqWPMDToAOV2WH9ykII3qnNarPzMf6QbGtA9+XEJw1P3fie457QflUMrUyuW1QAW9RXj3CdpyA0XWl7v69GhCW+ABebIpbYBRusC1DkAL1U16hWKVHHgqUV4gf8Fe9Chq1RalQUnIusIyrILaH9a4GAwAAclwJrHhLdDwcGeZYBVyM2BngvsRb/O3ChVyFYnpcM8mdwPauc5jvaBBKrdeyK61TlB6N6oOmNMsnvd+MbQGK9PFBrRFUzkC0+NgBC/hMn84JKFb9bM9QByG7MpRGn3SXDA8p06GgAXdN4la5zg9hm5Zf0B4pryWfgd4FuhV3KvyBM2w4YHORaKYN9xZtxAbX+IOODdualJ0330kxPW6dvHj7fPGxFcUQQb+/tR7E2nO8orJBmwWZh0YchjYeDSg1cD1y+YJUGjn6kBo2UeP1OKt09nDiSlHMp8EuHnvFBQpBxP6HevfwlW1Fg5bwtkTOlgAmJBltJgnn2qJpcbfTminqL9HbR7qWWabkMULUXBRWUSvixoKdphNXY++/I84oDc81EJBNgQz8ZglrU2lOzuPY1D/NDPfzU2MAwNrhMKGcVz2fQj6T4Ritr4wQmQEVRTdma8ST30CO5COXFne2c+0Jtnl/ASeYQcC8/87vsgSXxLQApyJARvqN14s+M1RDKVFG095u2ZXOboEbwN9cTPaDY72E387diTUEL8SKiX2kjnHME/eldUwbnuXM0raDbPpoUSzIunVEWrB21l/8hx823tGkHNjc20MuSe7gaDnYWxj9CZI07jHTk7KM+fVncOW8XC39kS/z+F7PcJbV+22DtWJkoi4U40aX/PuLYs8oyTC6NjvAaj0mgd0QVWF2vvW2R4XGpEIyIZ4Tx+CRzKGE8X9v7ysizR/XX5nLdr42F25yZM=","layer_level":1},{"id":"9b71fe02-5927-4a19-8db8-66eb129ecd9a","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"认证系统前端实现","description":"auth-system-frontend","prompt":"创建前端认证系统的详细实现文档。说明NextAuth.js的集成配置、会话管理和用户状态同步机制。文档化认证提供者配置、OAuth流程和JWT令牌处理。解释路由保护机制、权限验证和用户状态持久化。说明API客户端的认证头设置、请求拦截和错误处理。包含用户登录状态管理、会话过期处理和安全最佳实践。提供认证流程的调试方法和常见问题排查指南。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":1,"progress_status":"completed","dependent_files":"frontend/components/providers.tsx,frontend/lib/auth.ts,frontend/lib/api.ts,frontend/types/next-auth.d.ts","gmt_create":"2026-04-22T18:57:04.21635+08:00","gmt_modified":"2026-04-22T19:09:48.747579+08:00","raw_data":"WikiEncrypted:BenkIlLPgjbiADCpekIm2LnLFWkzmPKE+C+tunEqC7EVMaC4hkq7YX8EJXa9qt893SobX5KrGOKV9QEeDplCQkFx4neCRj4kZkvt/lObxAfDgMBruR7HQAasniGfUhUjW5KYXC16w7brsqCWR8CWKDQGEZiduwEsaDjAZy9TEu7PlK6Cp8RhkPZ9jhN/YjqaxTAq5i4xHmQz4VuuV2SO1LedFcTlV12iJH/vTW0vFyXgJqY/Ql6+bTZO2yMaEWan9rB7e+IsErvp40JaC2xqL7fRnfroIwQssGEvaqckwf2qyNjjNCcewd62C6FVDnxJOLjQbizlBKmbb8XVzuRLkECZVB1edGJKnDV6FkOkP9y2Al2Qtpbx/1Uhx1Lo92eRd57kA0Icc/KGcHKRjNsW0HfYWAtLctTH3fNIwtmND/J/6zKK4UdDJ8sXiTnjiU4JhX/fqW8bl4FVo8F+kJYUIhbJCQkl+qlYh/MkTCmyG8XukvSZGbvWMPUxyU1gMjDxUnyVdcJmFFt15oXI+X1CL6ukGEn1cRRDiB4yRAq2GR4/iUPUFC0d3aqeRj+ryjr6Cp8YqrHfONdwZyWd4hS8RPEP7NeRuD64yNRSDFTju1oPvBfROcmunn1GaAmw8dV6KtXSJnM9SaiqnYutX51ah9psTgX+UxTu7EU/ijnQYUnDLg26m2/bX4Rhm4MRyE/fAwzxOKEI3uIaqyun0W3lgdaF4bWTwTblet2a9rBOwbVP1xtJ5M095JzboruOAhl29fAT9iO2jeqpZBoO7zBim2s8cpkCt/Zf2Edu2CeUkS180PzKCBtnq0FpPLD9hjXPsn0GjtTEbwO6lSl9JdJ1+J03tiLVJjRTZffLUlA2gM3tucbJOfyGdAom4yffwP8hjrhTBeEyLwKmLISNARiKuE2Cm671yMn1pmt85Vu1rajq9L/GeJdoPPL+4pw0dk8/Oydx0+kOg8/Jyb/8D+XobOK98UfLB6gCaeqZV/2EBEumn1xdhcDpP8cx/kijjzPmOg+tlXa5VzG6SpcY1zw1kYgyEbLZMts5EHUFYp+UCNixZleiG2HvEN5v2iuXOdcZiguCFkQLt9TkzO1v99jj08p64LxUkxY7ovJoeanwleMMBEAI0vWrt1+8nf065/WLA+s6zQWMP7nlMloMXAfMybSF/he7s2xGsrnFXqR0XBU9qRnrLY/9IcroEnKTvicyEUylh+wG8KUQcIJj+fOEVqPGITla0i+36wx46XgzdRw=","layer_level":1},{"id":"b80dc237-1a6a-401f-9f4d-14190edebcdd","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"技术栈","description":"technology-stack","prompt":"为GEO项目创建全面的技术栈文档。详细介绍前后端采用的核心技术和框架选择,包括后端的FastAPI + Python 3.9+、前端的Next.js 14 + TypeScript、数据库的PostgreSQL、Redis缓存等。解释每个技术选型的原因和优势,如FastAPI的高性能异步特性、Next.js的App Router架构、SQLAlchemy的异步ORM支持等。说明容器化部署方案,包括Docker镜像构建和多阶段部署策略。介绍开发工具链,如TypeScript配置、Tailwind CSS样式框架、ESLint代码规范等。提供技术兼容性信息和版本要求,帮助开发者快速了解项目的技术基础。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":1,"progress_status":"completed","dependent_files":"backend/requirements.txt,frontend/package.json,backend/Dockerfile,frontend/Dockerfile","gmt_create":"2026-04-22T18:57:13.329718+08:00","gmt_modified":"2026-04-22T19:09:54.216074+08:00","raw_data":"WikiEncrypted:w0CkdCdnXCcvlN5xOpiEhEX3U68GI0Ngj6azFMJo9xRSxuOblJXg8Gncvj5vankATp2aJeXH/Zz4LVKH2Ep+cABEA0J7OIJMnt/ZJc7uvMtWJKS6+i5aGsUhX9BZcr1SC4TqdgwXb2je+DFK+fLZJVkri1Ne9BkEqmtSaV5CijFytJ/VSKFHzj8+7gC5Jd3CbEASojclHovCufD4dAVhlK2qcIuY3RBxMsvfRAlLyMLZEWg/gD7LEj0JaChWWR8vRaEtX0LtMoYIgSfbY/nUjR+3xHFig+m0qclK8Q01S5GJH99paLVqVkmt12iwMMiqNZypY1W2gRvZNsT8eanIKu0tq5HqvmbN0y9+nnuwnz/Tg6nUBlKIIS40jp2oYca9ak9bIwBm0TqkMe+M3Ara03+x9PgGRUuYwCt9d0PwpPG5/vOAkZtP8talqqwhn7Qom1nVkhmExMfsXTYsM+Fn2bQFXKIT/rAyT5rY6hwokrvghKwOb9pH7V8+4XckeKWV6L1rNcccOb6Inp4WcVBTcTvGbdy4Wj5Z1VETFwMnDdpOGFWc0jZRJpjrRSGgDuEW8IXpMvVYk3FV5ZyUXZcNyEWZ0Fp/s84guMC21/RYF67/9jD7eJYMeCsU92nWm6QkdVB13XQBOvYGFSu1QejQCgDMWpPz4kkt4yz9mgOtH7HsH8ZUDIml7Vci6pCcEIzS2Sy+BoXxSxcOzrqxD+PbGcH8A/BafN1771WuNzprCCTqbZd5MVXBKiY+qrlRCD1ug+pKS075xfWh/Y2Sjz4p1aJuyVplvOfNUKTlbZVBzQu5DBO+yhXj4b8Amf7OLydq0Avaf0gJhYhX3HpFNqi6aqT9OzPBIPohOUi9RWffBwHMJii2/NZj4GbgeXsWU5+EKE6sGFRGtUiBZGzf8FnB6rW16EA6in7Vd7Ls3pJrra3z6b/k9gqlh8eAVDoZhCPuxtA6yNlXm+RYWLDYeWiRDZoavKVj13rXtaqtX3j1/e1zFPMBZlDPVHyBqCZRiZjlKnty9cj2ASgpu7idyh8jDQSALGu814Wb55H1q08bvFxJf6pxn0JfbRJZMHqCEgInivdDUTcCCPOteDT0O2pwMmyHuq3mI3VzFPnYLM3aYzgJQsNIVztV/dIEJu2UGF/cyjIeROHaxvWYLNXRJZ05iMp8oelEwNe58eAvWt2KOuahqQl6xKUctm90QLv8QR9hr7PjiNAMVH3WsMxkqLcIUPuboMElVq3ErUqd4qE7W5l5Uxi2I9bVcnq4qiRtbCnRY32uC43wILTgq6KrBaO6dehB3eW4drPWqtmcU8rP1DJEatUWEvhpDNrI7T7wG6F+","layer_level":1},{"id":"7e5c3b8e-5aa3-448d-ae52-d5a96a413b0b","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"表结构设计","description":"table-schema-design","prompt":"创建GEO项目表结构设计文档。详细描述所有数据库表的设计,包括users、queries、citation_records、query_tasks和subscriptions表的字段定义、数据类型和约束条件。说明主键、外键关系和索引策略。文档化表之间的关联关系,包括一对一、一对多和多对多关系。解释业务规则在数据库层面的实现,如数据完整性约束和业务逻辑验证。提供表结构图和ER关系图,帮助理解数据模型的整体架构。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":1,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py","gmt_create":"2026-04-22T18:57:14.160671+08:00","gmt_modified":"2026-04-22T19:10:23.576798+08:00","raw_data":"WikiEncrypted:TWtD9cYU/QQHU+vD+ojNNl24L1Ao0zI5Y2mk07u9ZlXGce4CUXsGNCSRaLrvDZHw4OUpuZEJrmJBXEQX8GmxRc1IXLTgRlqUGmpzfcUAx8VrQijBe+unqg1mWTkYnMlYOqKWSJdISHyD5K3kBL2cL5pXF+f+lPHzSbWtqMnNnMKbqnSl/TkKh6cr7PM1YBR4IYmE21gHSR5XoQjbtYmg5qNyKF1kMdcAd0LHw6p7zHBaF9cNt++5GyFKLK0zjN2L8YiFsuFBSrn/M48QW3WyTrvDvqdOuR/Slfv+gUsKgbkt6+NEpuY9HPcRdvVJHvG9FZedomH4DrKuI0fUXgICXotXbrcEe5dOkLKgfn+gXmS6sPSZ1XgrSNO5gy2QNJaW+oKBuEPzfuKsNr3X19FZTz+x620YmL1Ccv/5uvf0Zxl6fyQb3qP+lsh2kaMdhWVKyoBv37oNKF7MO+fy+TWHFEwlVnxgmQREyQva5qxLyYzu1GtDpGp79IemnumltTAAzQ7LRs/RsaNcU3BZdYfQspjnhukylPJpNZtmKNN//XWvj023bGiaLyy805c71DcyqZNUs+EdlXmRTABeq9QkVU5wq/gkO4RFSgsWao/8f2i9FLeEZolKQXzoLnX7GxaY3BMcynG+DlwKFEolVOw07cpddYEWzmVKgJUokX/eiMbrokbcv9bLXJpHl2aP27B2FXy5Q2Ot11b2WbuT532RndBI+S9HQpfMmZ2z2Fc3VrWAbk03DwChHEbNHpmQvJpjKtLweVEpClahV8iTSwCkwd43jJdW+tR00iSdjt5vbl1cU7Dciah/B/9B7CDr9sUyZMjly7kzyWZqTkdXde3tO6tu6tWhTigIMXmZVqhW/pgVifH0R72VuM+sdMw57m7Z89ibQ7o2LewlMzJ4GsV90DdDhHQtUr++aRhcZp/669o8mijOQKj8MPHY+xjhZ2oiS6RHiCYxpibVfauiaXA3swWKIQrVCVE1x+jB07pieI3wHrmZf875mdp9rhfrz96+y4zJ464iINUdTQinm/zI4CnhXE3inFBgr8bD3pop0oYr2X5f8Gn2iKyvByc+w5r8HKV/7dd4GrdAosqVWpQweVEYR+MHRZ3AxiW+TCpRWz/PsHgunD4m+AQv5lxwoHVqF0Tqw7fmmxTqA/zC+dxlIJVD/R2WF4sFpA6femHOwqniwaowQerg8bGe7mz3BCSqiobqGSZQ5jQdh34TRP7qUg6PGkJx2NJ6AVIZVYBg9JNOQI67+2PN5AKq6WiT7Rojgo1r8lEx8SORaVptbL4YEEeD8Ec4g2l7Aqkhdxd43uw=","layer_level":1},{"id":"9fe32b83-3697-4939-8b10-524f5ed3e65e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"Kimi平台集成","description":"kimi-platform-integration","prompt":"创建Kimi平台集成的详细文档。详细说明Kimi平台适配器的实现,包括Playwright浏览器自动化配置和初始化过程。文档化页面交互逻辑,包括搜索框定位、输入处理、搜索按钮点击和结果页面解析。解释错误重试机制的实现,包括网络异常处理、页面加载超时和重试策略。说明浏览器会话管理和资源清理机制。提供Kimi平台API调用的具体示例和常见问题解决方案。包含性能优化建议和调试技巧。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":1,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/kimi.py","gmt_create":"2026-04-22T18:57:14.59267+08:00","gmt_modified":"2026-04-23T20:35:18.737652+08:00","raw_data":"WikiEncrypted:0zvMywNpoUVtx5LPNkwYYfwlM/Ie9jv+tKyKKcv1AxRC9mVBYjtaMmDbjB4bi6R3DoFVGOgv6ErdxCywJprEc4/FOXSuinoLipOBEjS1SoLvIuIvglY6l/IjgeQW61Rm7d1YcswwpmQZIzWMvqp6xJswdQOA6I4OCWZyyoaPa/2lETrzZcBW9ssD16KyXFVp96WbqY4mZhPFxSQEDiT4cUJ/clUzKx+oT4S+pSOYSGl6/5YsuAOA3Rc1HhY9Ow5FK9FlKsVMaFmxyJU/KLHcwZslXi8yzFzIWcnJQnRmMQlz6Zzz6mhJvkfg/s1TIOTiz3ZX906YG6DBXgZ66UywONJCeYpSAmTL6PJmP5z+lNRhuD0CzfmDGhErgZhLtvoyUfFoVruQmx/x9Rgy1lFnhKmvH60xIEg1eXiVjrQ/yktlr5ioCPigx1TWbcHspNlPAbDuKqqBhQtNOIgnlpoGgyEogad7Il1hkawUxt/TaiS3Lh0SN+zWs028ewgjO9gdWMB7xsAiB1+L5jMFCCJP/mhbPEfqnGC/VyxfevmgulrRD5A2EPR0QF4D/XNbc/vqSGqnIgkBngdxV4ibQlp1HO+Av79lh88FpVteFuEf6bsCL5SSHLDhJ8seJm0aoD1e6f+DtutdT3mVHaMcrEbMYz3AaNJhbNq0bEuElJ/ANz3eN0m5PPDjjnZto+CQ9o7K0C3DeRqKx2P0uRlrzhuBWIwJMzcC944SPjxYEUXHfT4C4vryztUifweDRw3eil4eFCrCBpGf/6gsdtqLoTPs1uBBVkxVh2UFoypvq5jwW2g9IkwMSHN/sAbNIITH2bRVDR7Z/pJay1eQSTjF1pz3NWcM6kQpB22XVAiOhiWPjJRQuWDtpRh+kOxWUSLaNkXSsf98tkydtHAPkMfUhalyLYFO/66PWyHJDWdFPECqtsOy5mpoJdYD0O/20+xc08z7liVDDgIlSocFXHWG35upSCjW6JWCIiphXqsI3He/dWHuwvTBamA9XB7Q44hTbQY3lKiTRjkbjuNfX8cmxcX7Hq21kTW6OBbxTVR55HSW1znrOe12b0sUz6V4Sk1zI5OB","layer_level":1},{"id":"cc7a1f1b-c70e-4c61-bfbc-6dc408a12ff2","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"查询执行流程","description":"query-execution-flow","prompt":"创建查询执行流程的详细文档。解释从任务检查到执行完成的完整生命周期,包括查询状态检查、数据库事务处理和异常处理机制。详细说明check_and_execute_queries方法的工作原理,包括查询条件筛选、批量执行策略和错误隔离机制。文档化单个查询执行过程,包括CitationEngine的集成、异步调用模式和状态更新流程。提供执行流程的时序图、状态转换图和错误处理策略。包含性能监控指标和调试技巧。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","order":1,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:57:25.383473+08:00","gmt_modified":"2026-04-22T19:11:29.353795+08:00","raw_data":"WikiEncrypted:l9Ho0Yh0r5bYH9QEePEhka2UMFH582eHsB+P+EaGE/r7Zj5gVUJmL6923rRlAt7h2uvHOVtef4s71D/S/eYpYYgI+wRFyPq+fQZYOCmVnMBRyypO5m8WqfyrsSGvviugw2fw2oH6ruNX2ul1LjPKkntbj4o015R9XwHG0oDdyJlipxqNUbh66IV2c2DO1besCA/q2yTeLh6EiHD+vYeG3HO5H+y8kykMbBuh9eydnmoXBTCsTlNBHH8gzmZWEBBSL7DETM0lYCiNr6WpRCoeZEo9ewLagGq1ammmMjcMg+7fO/xo+ZkkACRTnG2vnKh3if5fBjzo9tY4tGmtF7Fevx+yjLRfhpPsg8vSRZeaggRPgub5zBIulo/4qZhAvIVsyYuAQCqrwq6mBxAEjgWWrWjOThUEQOntbugUY0DitRui7XGp7tDjAIWw570xWzTTUWe0CMoHIPghfvhItcnYfjKK+fapnQTnz159jVJarLbBdjZT5JJfw9a+jlkVyF5RIKu3J03cjGFJeBf74DiMxFIMQkKzgL8jg5YiLQTisI4X0BBQrKHQvHzsD5+VzHGwCsz7IIfcdZuhkg3PIA4z4V7eZP9tOBUJdh7iE4fjhOk6fVDG5iZME72OxpBtFkmfrhwM52swaToCosj1eQ5m6V2GjsYY/+ZvaNf2aWn8vBJHI4IEO+Ua1mLHkPRT9bhDGS+Td2r1R2fmSEEvNQ+PTuhnRAyzRASTsjfWljzNWGNmcbCtClwcIuTSwPWLAoL+ANl303UlvxObHa9udiJcH3pZ86+A7iBLoCg6JxZQuCSqD0W6bPR/vozpiCvGs1TvMR5tx6AtfZGWw4JYl9wN5iPPaP8sPsz40D4PWkYIb4fIYY/X3r2iAnbjpV+/8+h3DQCWEdqRNnkZ4Do+XZGOi1yH7QaPOf/RN00+bcNtR36PnzENY47tg8VfPkbt47YTWHf+qvWfMFPwco2hLzXvNFmYN4dVMld5V+9mzCPJSIb+JOcDoVkoGuNq7aXnOVFdERnypgzvjryBt3W2LgPNlD3k6jR7pJAE1gKKrl00VSdDN9npu4QXyT49p+YMv9m8Jbf9xo1Jn2dqM/cJiKZi1FLR0clZHZ7nh7/7WxoEqbKnLWbboi/qyuTABO07nyQfmyXR/24bRp3AIRiM+7Bq8KL9ZFZs05JmFBtaRCAzWdBdM3TElVkfFOyZRZeKaBlk","layer_level":1},{"id":"fec685a0-c9bb-4048-baf4-40b56b2aa29c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"集成测试","description":"integration-testing","prompt":"创建GEO项目集成测试的综合文档。详细说明API端到端测试的实现方法,包括FastAPI应用测试、数据库连接测试和外部服务集成测试。文档化测试环境的配置,包括测试数据库设置、异步客户端配置和依赖注入覆盖。说明如何测试完整的用户工作流,从认证到查询执行再到结果返回的端到端流程。提供数据库事务管理和测试数据隔离的策略。包含性能测试和负载测试的方法。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","order":1,"progress_status":"completed","dependent_files":"tests/conftest.py,backend/app/main.py,backend/app/database.py","gmt_create":"2026-04-22T18:57:25.616681+08:00","gmt_modified":"2026-04-22T19:12:37.820526+08:00","raw_data":"WikiEncrypted:0j4RRfWJQdenLQLpT+DwLTyjMVG5sQffpuJQoSG8tbOVCukW9eq2bqobYYACR3zRn/N/FP6n0t+ZzbrLBFIDPbiPv5CjhNbth11wsRap1Da2YyKifcvwg7uyuWtSILKRIkP8wIVHX2/TkxRFQi9/m+9Qz3xVjYcNeOD0G8UWxzsSDqYGS90xX9MVwW3N24hbwwcJUE/TAMETdbhwrekpr33ej8R6IT6aBvn7m0Y93BRItueF5HJcUtKCizqJqcsG+BIQ1fodLPAsUiqvYW5dwymM89ASYiZXVbCOJq19yL9K4p1ZW1LsAc2J+6D8SR9RJ//D4gGwBmMTqxyP9bgn5eNt3ILeVMXWLXI9oxaDrdVs2Y4dXNC4AK1j0pegZkiNREUo54kWHFqCuQ6dG8dZB7BmnFEIYjwEeU29KdF6i0dyUH3/h5QjdLfc0OV75zuHQPaMs1p5fn3vo6ubXz/uWtxEF/IoVhph+AyY0Gci8TxdouTw4RZOm9I6mo5m4Y+TBsxUb9RO0WCrD/U7tRgIZcrxFfkORsKadNWm60Q4SRJeImUzxIVCUGBjr4km9AMwVsl94KSXmkBCNOFppeijE4N4Dl0n+RekVA2NBOau2woOIr/GwJ7b2h0jV/5/3x5hihxUSqZJ/q4RJmV/8aP30XRdYwZ6qiLcaF6Ic8kwpaS+9cvzGsPMcUF4GCS6ZSZoq4tuGj1ZY/iFI0w6Wj7rJHWbeBhsF/fHqFm2ijbrvn2nz+lH8Gxb3FM+re81hKNVU3BaZ3fxOAldPPvUxDw9tttWR+oH3F/gRkqefOIsw95LNYf2vIq/HXfNygn6mUw4aYidP1SY8flPcCMl0mDm7y7W6l+DKUJuok11v6h2AM09f0VV9JnGBMgwCic1FjQmfF2FWdqlsEaB0X4+aPne0DgPyIivgCLEq1dyneDm4TxA3CEVODVKHIu4fxPjmDtwbXUvPQe5sWkG7AEkp1Vuul8T/GLjJc/DHgUFe51MPFk3+8i0FCKo0x0fS8Mqm3spHB5W1tKYAIyexOgSkHzqgRdgERCTqUW461c4lKbFO2WIJqWgt/seMgxHr02Yk/pvMU08AaMRC974SfB7kP0lEQ==","layer_level":1},{"id":"b10c2334-a850-471a-9851-a1c698e3a485","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"查询管理接口","description":"queries-api","prompt":"创建查询管理系统的详细API文档。记录查询任务的创建、读取、更新、删除和执行操作的完整流程。详细说明查询任务的数据模型、字段定义和验证规则。文档化查询任务的状态管理、调度机制和执行监控功能。包含查询参数配置、定时任务设置和批量操作接口。提供查询任务生命周期管理的最佳实践和错误处理策略。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":1,"progress_status":"completed","dependent_files":"backend/app/api/queries.py,backend/app/schemas/query.py,backend/app/models/query.py","gmt_create":"2026-04-22T18:57:37.836674+08:00","gmt_modified":"2026-04-23T20:33:57.631967+08:00","raw_data":"WikiEncrypted:pNRlLcrWPaMbqj3wxGubppFNc0/AzaZuAQDxEKkb9fgIpRlV367n+a2PWiIY8g+kSLtBeyylocxMvW4jGcb79BLGGixlb4O6TPBIJc7v8GgK1UB+nLdmTHx/nT1JfKtrcPOkDjQ/yPHvw+ykuXomGaA2hiHzzBxAe+PbZILYbxYpQjnTqh7v4SGaGQ9U1E2EOXJ0RFpwna+s0NYfvBk+YvwkzRYPMiKcr+F4pcD5xTUWKMHZO3NuijnbDIE02fzYXvZ/xDBLubLxQ9Byx2dgdWxmi+xwo+gspb4v/DcrNll6qDWKwDnHGuyOQzDJJ1vXg3AaxwF5c2JyyQLNPUM7YV2kwxweQA08sFkJHAJ2yA0z4XM/DvAPZRdQf54LPlDB1zuFh8c3Ih5WaEO7+aTJM4YSmIYUbqjIjbqsMea3+cY2bIHXq2kdRT7uLikCktC9Lakrz0fFKLoJLovY3S1UBP3i7tCt6cmtMlN5g5hyHGqIVTT/fqAVUAc7wSZumMs4rr4uyEizs6t12KohwD2SqiCePMC+kbUpHV0fEBuzGlnYqPbW0yjiiVQlmIe8wTDNiNNa88JmcXkQB1pYhkAYrBUvBUN4Nrdf7lGBTIbQkQwvVoHuFah0MmoLuRQtoBqISkKJ9PMN0EOofu4pUNKyxmmcY87ZVbUNrwkgbvahp01NhzlsOLdxEa7d/74gFI+6MOrPY/6TcJqttksCQEkme4HWeJgRl5S2bCy3hlU9qcZyk6WAGPjVZg4JXdq2UbvBokHzB7KA7421mWkKGQALuZcUApNvwsvF1ZHjVau13wxP02WvaOzt+udwhgw2PXdNi26RDqwLhRL+GIjkpNfVngOcLfk1ULiMS87NXS9kHRTdXxu5W6PqAzyrgByrL3G+nPHL+XmMw6ntgsJdmtYmNWV0VijOOQGxSJGQHtaif6ZhBP+ckr+OXJ4GlkTF3jvGcfRkfx/eox+BaoxWI06xuXbFfImPuNqqa6odgzQzWv4CkvAnjcFq7umhE9Iri8xw/PDlUzBnr4HGnUPnAVvdomeMasz/oiPVTaI0O6tO3+I=","layer_level":1},{"id":"0c1d3542-92cf-4796-8dba-82caf2f7b361","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发流程","description":"development-workflow","prompt":"创建GEO项目的开发流程文档。详细说明Git分支策略和工作流,包括feature分支、develop分支和release分支的管理。文档化代码审查流程,包括Pull Request模板、审查标准和合并要求。说明版本发布管理,包括语义化版本控制、变更日志维护和发布标签。提供持续集成/持续部署(CI/CD)配置说明。包含开发环境搭建和团队协作的最佳实践。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:39.374243+08:00","gmt_modified":"2026-04-22T19:13:23.08237+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9Czfqaqo1gAmvHQcnSrNK3eg3bg6SLp6Qtm0Hd5JwzGY3jDj+dSShAoxbjZ6YvxA0ahjJ7+4npTrro/p0OlyQfTnVZ5PYAZZMMXhJM063eUYiuQW88+rNBbc3mKbsAdZboYndBnd6/wybElFnP7TORa5qWxWMveWf6U7O01ocA+ZnrQqoPWB5xrRfSzD1p3yGFA3fzKobYoxAAA3xE1ALEY0vjLN7vajgFVllC2Z6uKZOE4Q6v+W+r18Pr7pLXGDJM7b6pEfFCqcEMw2fWzUAFYSUOjSyg7j9TjP6Lae0AWOmmxIDmJIIiaY0BCv/iOXgg4F6QSChC8bZFyWJATWTNhfmHAMU6tYpDXqDsfLmRpczznZ5nzTtcX+87Ndpqchh+NWU4y5OYvzEeMRCh3HcCUDs5KrOoCJgRneV8BzAxfk4gCwSo2t2D/FYg1XWGfb6hPdmWzePBCYhhIGeDQRyAdApe2Js8UhXUOD3TM7yzFPMX9q5U9ZBfejCp8TyW2thbRzOL4s5Fto9PpXg38HbnE59l0BmptA7z5bTKTp4DHA8d4NhgCeDbfNLfSJXbyYaD3RqsQt8szzbxB2Q8mvEi8iUZUARZR0lyq0oEw3cYkZRo7Dcb1n5az2OJRZwHmvRYAm7KceVqa92aKeBUlVrfA7nOuwsVH+cEXyzE8ApglbJiQfTJshljzVBvYPkz0BxhBcYrnRIjy9TlqfTs67adZyWc0wqEVZeZhuYHwwN5yID2imZ/nq7cqiZCbV1dtBUUM6ayhVX2h/cBSLpHKAwVHAg9bb9V+RxXgtSYWYKCHsAD0ymmu/Fzk3/QBvrrFiVqL4b/5CKqk6Qi2dh4pN4tZg3zJZDuyx6xzWSrsHeYGnLunZQWtHn2lr2vR6+RqzRTDiOC8SizuAjeZP72IbQf5Xyyf65hS6yls8xztLA9oDCNnSDgJ/RiNDOspfgUyj2xemyoNqf2eJ/kCDdo4/VXxMiKVfg3MHY+Vi4dVlRcSEJYLU4AYuGqtqVhTIi2ESpnPXgDPAIT+ZZPqg0hLIIPx+HNqo5qz0qqxvliLlcAhizNT4MG3p3dBRI2IkylW4gHg==","layer_level":1},{"id":"109a8fb1-6619-4bc7-8481-e28cc2127d24","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"生产环境部署","description":"production-deployment","prompt":"创建GEO项目生产环境部署的综合指南。详细说明生产环境的部署架构,包括Nginx反向代理配置、SSL证书管理和负载均衡设置。文档化环境变量的安全配置,包括数据库连接、Redis配置和API密钥管理。说明生产环境的性能优化策略,包括静态资源缓存、Gzip压缩和CDN集成。提供安全加固措施,包括防火墙配置、访问控制和数据加密。包含域名配置、DNS设置和HTTPS证书申请流程。提供部署后的验证步骤和性能基准测试方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":1,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:40.355193+08:00","gmt_modified":"2026-04-22T19:13:58.697418+08:00","raw_data":"WikiEncrypted:1PcQ+NupkgQiLQ506NXlaizhNZeqS8C1INCZPnjb6ozpR9JAOMhzbAgtECu8k4VbH9zFlJ7iHctHtUva/hpzUaHUxVuG/rnK2RrcCUGVfbG0WKRpjG+EsQheC10ihbe51Rb+uXm+ciY+/SOxWBmrtK9m9jwSBQZQx2vXLOPvachfZTksEB+Ak0/Y5DF+vjL4WN+ym2SAYi7dW98iM9YCG0AepSeRm5DxENKRvtPR7m+w+vL7F2oISKi67pFiAATpFXSSgbkKjENZIgPfqc+pJfUREOrnHANiCx/oVaX2aOb68pluM8RGtAgyOfMp097D2Nt4PR/HN691JphbIyyeHPc82yGTjeuFPfg5XqFkhM4gvd9EdBLE3/6bh/MJhYjEwmN2RRhz7EYgLjSss8gEdDu+YLIEbHIaIC5fFS7gss/cJULC0/i3v4nnobE2Iqh3WdeIMAmynsin0sjO60LhvRmXlecODQ7+1EeQpMWju5LwTuVyX3dnr4CO4rJJxEBNYA4gaJuef2xo/ZXoun6cEIHjUq7qVNVOBZw2QtqBD2CyY3NULBP+nDD/NwjH/Gh98gl2Q0am/gLAHHoKcZfkSub1o1m1ZWTFgYn6MqyYv95NuqxR5+MSPb9C6/rwkYduPmovFsS2Alznry8TjsLdD5iSNz9MdRTR9iNV/A/TIIovgVogXlgCwnIz6EXZUgDnTeBTfTHxC+gwTrSKXUigRlIxEGksBJkzktpQA8y9mwnIfHgRDI4c8WEQRGEcKm2N3/ZPVOyBHSOHNpXK/BX8MCQqGoj0x6jusO9pJehw7KRprktlMbB0LmAuc5i0RYf9SnhsGs23W7ktzhS+uTjRB4kviSWZdHs+hgh1Pu0HsyBZxX7pemalNElQsWbvLwFNsJY1L1yjHNbBDYyXC7gZZqdb2l9GqKVgozQuK+qUUA0Vj2o6Cr4CxL01vBYMFpHALv8KnmAI2CuprX0c6PmsXV20FAFF8tIxoGfh7qcvquq/d4ONxZ5FZ1hJPYzi2xeCU0p8gFYEYYlbGMXdLCk0L5Tu0aDmTVkkrZlOHSIneYJDGZ1W/q+U6W18i48iBLvFBHD19jGHBgdzRuX551rbt4axStOcEGuyFrivbWK9R2zdcffHbiRtxe9wSFXxthLGe23JR42EF5PmZmMtlUhpV6alxUZNxguf+q/ouSz7Xn8+o6amnO60N57RyJjJO7O6+TgfHeroxL7CpABxkru/vXEJ5XTLqZBiECMMi4keQOqUbNZX8Ioct03e1YG7OgHtDSayZFtZf3kwN2ToVkxIRpLHTUHxSWLZu0YiAI2MONU=","layer_level":1},{"id":"4d5ac6d7-8812-414b-b8df-68574cc36d7d","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"配置定制","description":"configuration-customization","prompt":"创建GEO项目配置定制的综合文档。详细说明环境变量配置管理,包括数据库连接配置、AI平台API密钥管理和Redis缓存配置。文档化功能开关的实现机制,包括动态配置加载、运行时功能启用/禁用和配置热更新。说明性能调优参数的配置方法,包括数据库连接池大小、异步任务并发数和缓存策略参数。提供前端主题定制指南,包括Tailwind CSS配置、颜色方案定制和响应式断点调整。包含生产环境配置最佳实践和安全配置建议。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","order":1,"progress_status":"completed","dependent_files":"backend/app/config.py,backend/alembic.ini,frontend/tailwind.config.ts,frontend/next.config.mjs","gmt_create":"2026-04-22T18:57:48.684725+08:00","gmt_modified":"2026-04-22T19:14:17.843426+08:00","raw_data":"WikiEncrypted:aC5ZtUyEKPSxjzg//aVllKOp167MIMMk/Juev/hVoGY4+Uz0exYT+x+CbyScHHV/Mh1WUG25XsdoZThZQEtO0sLOn9+hGddmRIK1DWfKa/hxxPvnViNvXvltvNYiLNOIbKgkBxtXovEsADGNyhZh4ndOp+a/upcB9NJ4f0miwJacx2Kc2MyCkDCgUM/gJEjyoB9tRPRJVPFRvprzmaiPXJ1K8jd+KuXwrM12ogUA9iPZOtJJQTeEXQVIItOZYzY5bzAZ/mnRyVIB11vegQ+E6Lzm7D1Nza2QOZ2893Bzu61StECZsNlfecc+xEh82aNHrbFip7Fg2I3E3fqBs5EgoNXO5Wnvkcd9fHCw9vI9kMJucTIPcthOyWAFiP56zu6Hzknqy5N0o2gSAJQdhzzEvIUUKeeGDZKSY2EjFsH531gWa+Q9m0FsYWFcErqBlQXG8K06rnNNeMwR71GloOifAK0ySuik/7BjJ7xIR7HF8FOfSaOhI011z3GaEBxZsMfPc13v0joKHld4p4PRBXAfExWLlfuM6cmB/77U4xdBrHVyMcS8NPKuT+TQCTzjr2uUKzxUcjbz+yGbjVFGKMaVzKH0UQfLKeSDUnb1JNBrQWR0PFAuZsPZt730dAHdElNx9MenV8/GY+XPklTXdGMUtflT6CKf3fLy6ppMVbMDph2Ov+1Xh3z35Y5Mz3rufJasyOE0rZQMNsUu3wHtnjYprxfzvmpP9En5z4KoGEa/282c8xoLp+n3+etuGCN2aor1BSrro/ZpPTduyQtqj2WdfXDnZo1In/RRAh0TwqPze8Cd244OFfKDDAEICSSoZl0S/2l15QyTbqDNVnRzLndJswfAi2yfaVOEkBHvZuDQZXmmlf4VGsJYihVUwG8Y8bvegjLxgcD3LFGNKjzuKP1eAYLcotF84HRaFwNG3hz8Mv8puFMKyrHVKIC3UxzBVaialQqdO3oFRcrLdcSIx1JlY2qhK3BsrUtj0OLURUs0dBnCQS4ndq4NTLSQECFIifA9l7GSPXyOkGkp0+H5QCfjOl7L/3EJ2o+lTisAZggIZSZ57Ig3WxOGp4tgBh18ubr0TRNi0u/VccTbFyT97irQVq+9KNBKwPZZazaWvJEuqNSsdX3WGjh17VTbbZgmTkAwLyuCf+nyKkGUkq6MtRYwX17XkQuhceFpBmYkoxlfSWr4odGaspQ3c/AJ5zFNMigymGGpxOynWRWD5Abo/3R67eqZ9rZbmCqQbF0fkFPxdi1prJr87dubXtG1Zkj8AE/ZGXYjwas/l8NeDYxLFeir/ic+yR2tcU34lFAY/B86IHf+EBSbBYigErIEadb9gw81","layer_level":1},{"id":"a232faa5-28b0-4235-8ad4-b082fd226e69","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"订阅管理系统","description":"subscription-management-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/api/subscriptions.py,backend/app/services/subscription.py,backend/app/schemas/subscription.py,backend/app/models/subscription.py,frontend/app/(dashboard)/dashboard/settings/page.tsx","gmt_create":"2026-04-24T11:02:30.91857+08:00","gmt_modified":"2026-04-24T11:04:05.339576+08:00","raw_data":"WikiEncrypted:esVoUJ7ZE3JHzIVFBls2kBN3sRNq72F+2dVFRiBKd+IrKVrEmIv5onipM8erIVXb1pP69wHz5wuM2zNLXG0Ok25RXMybvVHkFqWAEJZpvoheUZoKQmWosbt/UANV5ZMnjhjv0ugRLP8tCwG6HlqUXa4nXCgq5eT+9CKzBTZAc4gf0pl58FewLHZ717UOV2vGW8V5Sc2aVmo/U4kxF9AoGPen+UMUBOILg3LRfP1EM8uA0NcfMu0/dTEUhVAoYdg3egrk6V0LTUamV5NV1SNEVaJfKvMAbt0cYc8sTySSeM8Snn/OvSpnZV2OyrhySqbTxicufzGyCTg/r00/80Kp/vQ96wbKsGjdmbm1F12CjGpKngHQMvn6jGX1n4TtKe4WXqhzWD8nSBjxmMuHQfT8IIpn7seKyIYsAno3TuGU8reVJsl4T9zxMpyipiCssZHp","layer_level":2},{"id":"9ac86c99-3b7e-4745-bc95-9586153d616e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"管理员仪表板系统","description":"admin-dashboard-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/api/admin.py,backend/app/services/admin.py,frontend/app/(dashboard)/dashboard/admin/page.tsx","gmt_create":"2026-04-24T11:04:06.082629+08:00","gmt_modified":"2026-04-24T11:06:01.089787+08:00","raw_data":"WikiEncrypted:VQqnnGxIj1CWE0rWwHbIomxfew9b7C1uZnUxTSvoHNsF7jhPgOFZS93QZowJJe0Bae/WW9gTFISgZqZ6JAIQlKjp5+H4hYIxP4IyhsAvFP0LcPKdx9gdtkqMwGuidWR2jaXij4fO24hbtjQmmqGXzUUbNnTur6SoiIIKMQ50UFibNp6+YGkvBNWvYJucvpgox24f7/W4o623WN3fB7olfkunOV4HVtCrMdz7LTroAFTZrFhDQtadQmH2JKYCypsT6SHcUyxNUvEZKgLDm1LnOAV0ZyfEx3DuALwEmdt1djL4f0HygoGjNMpqhiA4vnlg4puNMiDyY1yoIUNQDPK+RQ==","layer_level":2},{"id":"d54446b1-5984-4fe6-8fc1-ad0322ab7914","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"安全增强功能","description":"security-enhancements","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/main.py","gmt_create":"2026-04-24T11:06:01.807432+08:00","gmt_modified":"2026-04-24T11:07:19.927506+08:00","raw_data":"WikiEncrypted:6g8iffgXzed698CsRven+bBahvPZ7dIWZ8oYo2ql8SUqS81oHqMdt4/8dBPkLJmUIV4rpltw/NKHLMVVnedRfw/FNgssHH7lJc6ouSeYuFX3t4LMNLJCZkqOnMgC+EkvVhhY7xeMZKjKAR0WN5yHtQ8nh+sWXX5BRoIgiZVs+G4ejsoPo06ZZ7dCm3NkqT1esGxyyfRka2pRlAtMZopE67FJNPBax6aDb7t3Tp40D3FqwBrnPkLvNpEpjadhQJLLGbUZ1ZVau7pWleXvys3qtdfdlpt3SRU3GxhleT5RyWyb6H7xliffBBWs6e2+EPrg","layer_level":2},{"id":"d645182f-1eaa-4439-854c-0437806ceebb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"PDF报告系统","description":"pdf-reporting-system","parent_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","order":1,"progress_status":"completed","dependent_files":"backend/app/services/citation.py,frontend/app/(dashboard)/dashboard/reports/page.tsx","gmt_create":"2026-04-24T11:07:20.621291+08:00","gmt_modified":"2026-04-24T11:08:42.188151+08:00","raw_data":"WikiEncrypted:JtXUgB2EREv7ncJ+MegCx6wn6P3rv/DbcpMX2oD3DhY8Q8TNEnThfOLhKKIJTZNfzlKgubFFqtmmSTVW7QSMR71tLjgZgSLACwoE6wo1/FhEifj/8lOp77v9Aa5u7WO+EgtLVWSz4kKO750z4owTufvhVR+uZ2ahVoHSKD9mXo4KuqrWwFr60hm65igoFdhy/Y+hyNsaJejQJMCUwntWiPiJoBxyTIgf/GpbNj3Ed3Rz67bKvr4/rnGpjDMYKrLKqH5QhLo8wpIaf7MZcfqc6GYtYhyLXCLk61wnw7Xgs08=","layer_level":2},{"id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"后端系统架构","description":"backend-architecture","prompt":"为GEO后端系统创建全面的架构文档。详细描述基于FastAPI的后端架构设计,包括应用配置、中间件设置、路由组织和生命周期管理。解释数据库连接、ORM配置和异步处理机制。文档化认证系统的实现,包括JWT令牌管理、权限控制和用户会话处理。说明API接口设计原则、错误处理机制和响应格式规范。包含系统监控、日志记录和性能优化策略。提供架构决策的技术背景和权衡考虑。","order":2,"progress_status":"completed","dependent_files":"backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/services/auth.py,backend/app/services/subscription.py,backend/app/services/admin.py,backend/app/services/citation.py,backend/app/main.py,backend/app/database.py,backend/app/config.py,backend/app/api/,backend/app/models/,backend/app/workers/","gmt_create":"2026-04-22T18:56:47.08233+08:00","gmt_modified":"2026-05-23T15:24:02.349698+08:00","raw_data":"WikiEncrypted:7Nn1MUEMCjrO9aPSED6FHT454wxodEJExHk1Z3tdkRG7psPg9iIsEKvTk2vItDaJAXIG4d4xq8Laz0GUpWi7tvVyLa03YCfOyluItzeFyggOAAnOECGGCu8+eZnrHGjCrLMORlQ+1wEw9nkOpcZHrAs9OhT91iKgU5h0B74rt6WjaJ6MNzH84B64xYyEqmHM0niEHypbMjA8WO+d7J7BmhjgtxWBkUJMprVu/3XnDqSwD4nrvstGxDp6a2Me/1xldqPAIH33Bh7jHl8jwBH57j5llwy6peK7Pcn56nd6/IUHuPpwTrnoc5YduJIMKWGYxu1xF9PNaWMAkurHhHCoMemJuTlpc4HVN6jdvDHV1XLd1WD+tWrKhA2iqcmzuvaGu9XkVGmdF9XSUr3QcpLHFeBkTanbvFYTANI7G07mjpGtPOIvGgmHilbbqh883xvi0eQEyrXDdoAqA5jU+paPRtXoLxib8JBQEqB+fcKcniH+C74h9BHKdauZgcLRT46tYmeFNQiyrNO1vcm7emWe5DFtjbfwrxYUv0K5IY6AUMUzoATIs+eb7f/Y0X4T56LR9E2aUyeViaWeVtnLMiXVSgRMz1/fAG0OfZ1BYXRB08PvPctEfVdY3C2FC9+10XmkN/9fasMBvjcmO9WvIqX6eguoLy23soTupv+OrVuoZ6hiCfInpOcYV2r/ApKBP60ayqitCwvs+ndNATQGz2v3VVvoolt8ZIZvqhvzyOE4JAltTznL18weTTPLWlFYhCPnG3qPm4/bDu07klIkZYx7sKLgTJk+q9nrNphi7sFpmzfC6wnhOtCPR6moX9vrKxydsmZt9cgBuSBia2j8lOQuW4fB5z4WqWJ77Tt1H5EjT5vr3XU4FH20+0eYQYPZNXm52VxrLvB9embAi+nRLiJ1efhYYT/43T4PaUpLTjNMd+g9dYZAgDJ0SVX05PLYNgf0hrDicYjtZkb1/nYUORVOB1zsV5Vlxd64mw1OyQeTokBZYMIKVwfz5UppkEO0an24PaWXjGBnGwjQuDU+aQcm41Tzj+RpNOs5Jgj4MNTv/O+qBC2nvJ+HzTDKmL3LiAV7NfixyGTkrgW8UwAIlDIoPw9OhoM0cQUt7ngzx0vqevePxkh+zyEVs5vjLNwy/sC/UnJpsSsSAlFZ2knnjVE7Og7MI9qWikoCxEYO0qe0Rs33TTI4BlWyFvy4ts/7qO5lG7mkLjHXKv9351kbCuJfG0L4w/Pe7iuve16Nb4unvEKDxYCa+6CzFAjLIsZa4BdOQRsVxyUXf9P4rokWxV5I9sV4jt+WMARYpD5jvN8S2SOqqH6mgcz6Avyd7Ae/46d8Fwo1fLqt+vaQ8zAN+1W6NxUD3NRJqtbcG74m4zp77sPb+jKwNzpnAEewLzpcefAjyBDM9G0IQkgIucrvTCPUr0dK6NCS1H5VIGRNHT936f5C7AFiKxngxFR+EPtBbl3+5AB6y/yxA6jOwcyP22+d/rGsqnkMfxru4kZXc+SJWu6y5nLjRGUBJDZuECrt9WAGscutosi+ugvzvbZwXU8Ws3Ld2j11PJ2MFiPdItEBwKaK1uaEtnFGebbA+g4v2w79ingJODsBC/sZU9N9nFi37WgPpulaDGOkX/9hIyA61F1KNe0Qj5ACKj+VZUN9BdhIk6DNHWMVTRqAvdbP6aXn5Xe9uIJ2hmLtxltTcZMh/YQxM+FUEN02HPI9R2mkP5qg"},{"id":"159f2ccf-71b7-4d1b-a4c4-c15b23a4126e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API接口设计","description":"api-design","prompt":"为GEO API接口设计创建详细的规范文档。解释RESTful API设计原则和路由组织结构,包括URL命名规范、HTTP方法使用和状态码标准。详细说明API版本控制策略和路由前缀管理。文档化请求和响应数据模型,包括Pydantic模型定义、字段验证和序列化规则。解释错误处理机制,包括异常类型分类、错误响应格式和HTTP状态码映射。说明API文档生成和测试策略。包含认证和授权在API层的实现,包括权限检查和访问控制。提供API使用示例和最佳实践指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":2,"progress_status":"completed","dependent_files":"backend/app/api/auth.py,backend/app/api/queries.py,backend/app/api/citations.py,backend/app/api/reports.py","gmt_create":"2026-04-22T18:57:02.317509+08:00","gmt_modified":"2026-04-22T19:15:14.078939+08:00","raw_data":"WikiEncrypted:xKp6XrvgQ6yDy/qZb6DBAyzRhY9oY9wND++XWs8abaIu3G2LITgI+Z0UQBWYGKhuTqBsuTOr5OLyKixlekyR1Xfq7usrLYQyUqykz50fvTC/eHiVp24qJjGIE/yM/QXCeZCQ0Io9avqxwyMLsy7oz+0kRVW2WjLzRO6OrvbiUY+8yPMkSPi3UCtyM0GVLTpD/1yhEPFlJimDIuMsn1U/6MxjS0vcd+yEDjCBtrAoR40VIxrMz5v+dKD/pjfzoR1p6GEjf7b6zpzZGPhEtFmhzIahThZIdAaGShFz2YepbNwjns9s+2XJPvMdDYb5mBTcQCjoCHeUfqpQ5eRpjJ47qGFAfFw7lpv7GfOixRgEasUkVhJaX2fS+R0bGg3mmJFfg8tK9XXCm0OvNdgj+aJ6EUKT7GWXDkWLJd4NWEHKvqO9jfXu7YBJxM5tfR1i4e7CPz16fSaCPJtKsI+HgIoTf1JQ+3TrBqGncHko/5j2BznPg08EvIvKnECTrZEH1ATf3+Dpz7cY5x5f+D+oBDxG88V899fkfZSrXbY4YZJnhO691mRZPnKUgr3TsGO4kK0/eZw19HvuCyKxuqWlpHvV2nWGiFCyQpLul9lskV53bxNE6LCdF4LpQgsnxp3NRkXRo9kqVcTFEVZX1D65nknWMQHMOr91wEbFu5y7eHBY/M1mlvT+FpX/uzM6NvEAUkyKHsIpLihbh/obM0dUOwFr/y/hUOLfs5gw3aMosXT7+uwJRXkzxJlNzCyzWUQoMQbw19Mq53uhogOLGeVQNV9+lYZlsF9DEbUg7pWX1HOTZw0qj0G50JKHtiM0mGIwmRxZy7HDNhqrMGXboadds7LRAL8up6y1uZya4V4Y43X61XVoJJrERnU6caJROOJ+2I5yEbNYOvo/g+dDZf6DLrj/5IPInHUF/rwxMPX3V17obui48Yk9OOgLp3s7TEAU+t97lkEPo58h2oDARfsbxrnrVd0I9z2/IJSBouFoAA5+wGUVU3BH0Wdc9bwTyjJg6t+iiz5Z14RRB6hnBI45qD3U9a5fIJ1mWWGl2mBaOfvJck5hTbq7v+Au4iOMprm6m9SIq8C9D5w/PtHslYGeBDUYeIOWciDfxj90/WlNjcdIpE8qX8PqRFKdnwDCBOD0xewCH5Cw+MxNEuc6RRDsFu6vhFjjYe/vtb6bNc674kCJn5eQOGFAo6+v5wfkkZhG1S1q5EY8GJf+H3HgtucPikTjpKAbpBkkiorIBJ4n6Gdi9Jof2lYe1Ina6yJPsnNyd1MyQgdpEg7sStrvevt6IaMoeIe0vQ+WPecPhqsIm9X4wS4nI7Knd7q8WUsBQfphwlTzUb0igehWxKagmMc8N3x64Q==","layer_level":1},{"id":"9cc59a5a-f597-4707-b994-b6c49514d553","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"页面组件设计","description":"page-components","prompt":"创建页面组件设计的综合文档。详细说明仪表板、查询管理、引用数据、报告导出和设置页面的组件结构和实现。文档化页面布局设计、导航结构和用户体验流程。解释页面级数据获取策略、状态管理和错误边界处理。说明页面间的导航逻辑、路由参数传递和页面生命周期管理。包含页面性能优化、懒加载策略和SEO配置。提供页面组件的开发规范和最佳实践。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":2,"progress_status":"completed","dependent_files":"frontend/app/(dashboard)/dashboard/page.tsx,frontend/app/(dashboard)/dashboard/queries/page.tsx,frontend/app/(dashboard)/dashboard/citations/page.tsx,frontend/app/(dashboard)/dashboard/reports/page.tsx,frontend/app/(dashboard)/queries/page.tsx,frontend/app/(dashboard)/citations/page.tsx,frontend/app/(dashboard)/reports/page.tsx,frontend/app/(dashboard)/settings/page.tsx,frontend/app/(auth)/login/page.tsx,frontend/app/(auth)/register/page.tsx","gmt_create":"2026-04-22T18:57:04.216604+08:00","gmt_modified":"2026-04-23T15:19:43.818179+08:00","raw_data":"WikiEncrypted:5oI5y1yTFbg14yVSXHYDGFeITEbIkjmdES7qr/P4na8TrPHqKZDCV0OwvONxgczey0MsZEE95T/q1IqTn1MDXDe+zweBCSZSlefgNsHwrtPEnyqFrV2NhO5nKlcD6tYwGnW5Ag8vX/svtjfAjl//gRYZD89hOQGnlYrcSU5a6FC1LQaaD4KqNgrn7yYxshfLveO4k610B0mb5BrOdyTpLLBcuNmEgY9/GKvdoyt0cfpZPwN5J+wPoYjAnGjm9LDIkL9L02r9Lvvq1mhN88A7yKU49c6lU6S75IzcT+OFjTd7OXXastuPBLJRb1A0sFMKjZVshweginUNg6fhc3vFQ08Hthoizv1Pjm4qNnloa7P3w/rnuQrvCJk3Nt1PWn+ouHeenTb9bsV/KwF6BGJ4HGDSDyFcd0YmY4CDfW5aSBFP1QYneJUBxux4dxgw1GbBsa6R2o+cDCB4DqSA14RqNvsI4r16PlAraoYSaQRYj8NQzY5dRbzpEnhmyPsBmgzcW1gLo067XcLiF0DJvlouezCyJW+Y9YA0fmJslQSYvcMhcI8mYdAfGDi1EoXoUiQYMnvlYq8J8ktBwLbIskG3FgeWvmoAFZE08E9APByPtLjDcHHan03Nwy7CPZqb6FtXLeHH6H4TK+WRnxyWWUCCGwQxVYXq0SDxaUvHuhZ4XUr7+Q1U42rlW6cND/0kiOhqZxe5qp/7PBom2IrcPdORh4lVv3RCQrIDCkHcBzCV+1WIwFeaxUaSDNJMmZ500JhDl+ECx+6dgbMAMTRPh+SxHxLd/OJMI9dD9eWQZMj4RwDxTbqlVp8cpoAEGPNvmweo2JApNndlNo1gDMJ++de+I8cKsyCdEsPfQ8ikJHY3R/UaPh/mPp8pQaKIBBP/nvMsT8jYMtdv59ejwQy6+/9dplr/mqdQCkRA4B/maZQ57aFmnsw8HZM9ukvo0Ni9KpUFM7iFAVdZy3NGVf8DX4J0jwAjd643HXH9I6+6dP2Jfs7ezsKz1T5yAHvocFPqxtbC3b6WrwrjPWf32N1a/qM1RiZdPyUNGE5ij+CTm9PUzcQxUcatfkjdDGnwRIAJMmmrtYVTBvCP+xUKuAp2UmXU9xfTYxlU6rdp5LyGQS9dHP0x7KBg+yOWNzECNEzMiCgE7gOqv+X75WA7D/sSBMaO52H6f4qtJovvnkwq4r67A/ByroGz4ctZ/wSVqTHti+gzlXIxgHKWr8VVq1HUFUCSRdZH3Q8PaR08vmQcapIQHpDRW13nUf7saKZh3N6R63lREJu04Ie+fQ8i7VUsNE4QclcrUsdj7eUxv5xtz7xrCEBDZooPT3RW8OM08MJ2Qe9sU6bdCvHTPE21OkEYFD1tWzWH7149QZPhOzkXIQ7qGdKQlmRvyOnd4uL20k58I3p/q9ktqLxBCy5s9Ac6PYODpXPLAelkYzhV3TcJAzxphaGjCmR8goNGJJWsqw3FOOCjGqWliL0JmW23Xo4emXDMUU50N9Ru8dM6NBIs6o8Hy3YcM2dj4t5RwlVejQhCn9gwtm742VYEdCEYKq+8FJtp49Xm01KPOtgTyFN0lF+HOQG6LCrIBY8cXRQtkck1aTvxD+KmKoVxp09guujaDutV+eyhyb5dYSytjq2ptL1FsYHLS14Xa+GW6DEvniGGnCzP2LTzntbqIVzx3J6F7gquTfsiDTTPkIijyYxWvkSseJc=","layer_level":1},{"id":"f70f5d9b-d7c7-4dc6-b36a-5f4508e6acaa","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"系统架构","description":"system-architecture","prompt":"为GEO项目创建系统架构文档。描述整体的分层架构设计,包括表现层(Next.js前端)、业务逻辑层(FastAPI后端)、数据访问层(SQLAlchemy ORM)和基础设施层(Docker容器)。详细说明核心组件之间的交互关系,如前端通过API与后端通信、后端通过工作器调用AI平台、数据库存储业务数据等。解释数据流向和处理流程,从用户请求到AI平台查询再到结果返回的完整链路。介绍关键的设计模式,如适配器模式用于AI平台集成、依赖注入用于服务管理等。提供系统拓扑图和组件关系图,帮助开发者理解系统的整体结构和各部分职责。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":2,"progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/database.py,docker-compose.yml,backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:13.329904+08:00","gmt_modified":"2026-04-22T19:15:17.452724+08:00","raw_data":"WikiEncrypted:gWB8HBj+8+/15rQhXgtMjCy7qJxJBEw3w9EAqc5Otte14+SfcEK3DSbmZRhW2TgD6BlsxDXHpLcSijck/Nymh09xxwlFe9hXY5fsIsj1IZW9egIbof/vmRQ/HkxJSvNy7WDeHEuuU7TDae+7kls5UELL0/oUUiCC4fjizzoaOlqMuOvW/DImO8fA0xbQ2wAt6L3bqB1pcGWvnB10d6EKKhQYmUj8xv/2M3cUBtDMkUdyKbAuduBIInt+jZnOGnXKcr1w3W66u8elz0iqgWhMCsMFd54QokMhn1Uyguz3NcIfEVH6IlKil0ufINdb2d/QV+9aukLvJ4Mq4YDlUjQ2iJ8oxAYYUb8eIjBnsLHPfBnMUyXVAo0tbyNB7wUmRb/L1VR7ipOMMKd9mEohzKGpsTxHpM8my7x8Ryc9N1guO/H766qiiNij1HNCu4rWVW12oeTTjAoEKdLzLyn59Fc4QjYVkS/I+r/lwRtMNN0OGjWXGXea+HUaIHwW1088PW3eZj3FlyGEsTiYb6ysJAWanY2qoIhASm31o8s9DekhdxTRbWeBCNzGN2ufTYGM9ygKNDHF5dCbVW0/Vtc6FC/TDiflhIaDY44Gvuu84O4l7SRBl0jKM8uCFHOgx/NzDlnUdNFaSOdjUBxQ7vVyi0Q5X6P4H/ERPzJQvOa0gmXW7S1ry0P4/CRjOCzq0Afw+mAf2j4PHM/4MWFkvrFkycbEkHWoWnPY+DWYI00TVSdTWjj4n4l9wbj1XDhXavLdg00qHVjv0dTq1ghcZKv3C04T5MfvVQjMXCKPQaK0KzwZDfXydWnlyLPgM8t95lTETMkjjEpIMtiv2w1gJda4ChFrJq27oPmVlEoVzGPuuk2B4YN3z6A5y3ehJpejis1/EuBjd0vXHhwghZeUv8mMD4smRPUMA8GcEeKVs9TQgBHqVuuVDdEAQfE7w1ILarmq3trYAuc+LH1KMUyPD0aZEbhKZdMRkFYWLhfyYeuazm9SfO1BqtEuTVoAXdLD86TCQNmxxTZPgU9OB9JluopAMt1oszBwKK/88UqwBqgUZle95RTKVR6QPn7zAGZaDbfsbYvsGUfNBSH08o6nnraxB0Vpj+r6WaoZLCcxhqSWoTp60YlMt7BDsla0Lt8r6D+a89AtCqZOHLJbrEx6T4wsmiykEi1uC/9XhtcsTHuytq/rHeDWR/bTToB+mGjBipoGscvIFMgUJonYCOjLDyBPGpeWispYZV21bIJQtFIYv06NKYU/IV9ZISLel9AttowTEXv/Y/U1xRtmaTp3BgGI4iRdwXYMJICv7Jyr5kYd2CrLJQPzEBdkJi7+q3WNdTCWBPd3B3hL/tTL2lFNDOc1sqMga78PcdWWHQfheORW9OfH3cDRiq85LJziojysfwkQVqHY7niPkDyphAwn9F2xZZl9ZfahAaU07CgK26wyavgkYOAU0dlWI6WrAKE2gQOzOxBL","layer_level":1},{"id":"816a2805-76c9-4f32-a3cf-96428208081e","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据模型","description":"data-models","prompt":"创建GEO项目数据模型文档。详细说明SQLAlchemy ORM模型的实现,包括模型类定义、字段映射和关系配置。文档化每个模型的属性、方法和业务逻辑。解释模型之间的关系映射,包括级联操作和外键约束。说明模型的序列化、反序列化和数据验证机制。包含模型的生命周期管理、事件钩子和自定义行为。提供模型使用示例和最佳实践指南。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":2,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py,backend/app/models/__init__.py","gmt_create":"2026-04-22T18:57:14.161024+08:00","gmt_modified":"2026-04-23T15:21:46.785144+08:00","raw_data":"WikiEncrypted:Zb5TNaG1u/mRrgPr+sDyCr47uD+4y/GruMCqF9C9nxStxKZi2OWvk4ViC2NJmWUO/Jxugi7iel+AeINiHAz9c7erlmOh78DEPvZI5zcQaIYzm9l0e6yLGbMS64gON4GYqx4TUizeLGAIntFG405vTATENZMylmwR0jTbWx2uP/KlAPch72o8TGREvPTy7FGikY773VIwNZq0MXKYxjbwvld1ADWYjtxMoKmZ7pixx5LeZM3O+bfisD7UTqLobS2VvR5Ic2ynsAkEEzef+Rh5O85TXra/uluSuAOST9W65TENzfEzwHe+CNAQmUp47/vG6d7I14WPEipc0/aKbh43AhJkclnRjpR0bYFPJrW/HuN6chk1uhxzBK9sKpOUOLZ5MffdIttkTAOz4Ny5MxnUwt0zj4hDsVOevpasy4FZ/3pVx07fb7SlIDC18p+OUYQIk9JqBxZmgeMslhOBSkmRTAwqir6PN/GuLEeeC0mPlAMNhsvDrklfLlJmLY8MuSQHqteqYJryoZ1cp1yeqxATnDfeigUr8eSSaFqZc5S/AlgSIrvr+7XJWk/Oz0wKPLRXNUcG9yDweys2pdDb/hV5hiTmLYjgvYvnDLMMjrFgR6Fogz3U5ItD0xLC3lt09GJfm8jhS9E4AJd36iPN2WMeHsM0ctdvzYB/MKtWIIrBkWuRD7CZeGJepiGO/GJprp9HK9m+APjZQ4oc5d43tgDModdepglAEgNklY7IzUAPW0Qls3DhfUUHq/Zuf5AxAfUAAg1JOW2qEQWV+btkeoRPEiHjZXFDLGsC226d9yUlnYcTkFOeVbL2gomt13MPt6c4EQ3y4BSoG1CYqO0q6IgkX6a4g9QE7OKjdE3RX8rNGixxNJzfx3oeGtcne/lDvhO9/U5SlpNgbkkemAIPu+eZw1zMpknFdRwUdwOwgyVNxR/tt9AEktJ2gcaxRGfG3xTSa0JHoniO9otA8VI+Paw/il8qAI4Z1kf2w+L8LavGt05hchhlzWcrGbBjXF/VkCoYxFvM6JX9FafcLjoT3FtVTSorVysHodJyR1nHB1TL6/SH9v5IZMlZeQ6/Gm87g4SquVaVgvEBMuFPA6c7BBhWUqGw48UIBxfB3Ri4l8HYfRBiqrPSIuldaD+xTVL8F5XsVhczS4JXDnX3RLtvjOuBZRcejVO0ubg+syCfBhf+6CtYOyDTTQDGgwdiNg0MjJnmjy5TMmMdynOGSm2oF6wS+tUuWG8lMMBtredaLHdyVb455+OY2oQ5hJZGo7eyzchNabr+Xous+Ve/4cM2FOoHdQ==","layer_level":1},{"id":"64cbb894-755f-47b5-854e-c26c7821e9b2","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"文心平台集成","description":"wenxin-platform-integration","prompt":"创建文心平台集成的详细文档。详细说明文心平台适配器的实现,包括API调用封装和HTTP请求处理。文档化请求参数构建,包括关键词处理、请求头设置和认证机制。解释响应解析逻辑,包括JSON数据提取、错误码处理和异常情况处理。说明配置管理机制,包括API密钥管理、请求超时设置和重试配置。提供文心平台API调用的具体示例和错误处理方案。包含安全注意事项和最佳实践建议。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:14.59287+08:00","gmt_modified":"2026-04-23T20:31:50.506814+08:00","raw_data":"WikiEncrypted:2Sm2Oxxfu6PsmMr2pZflRJ0uQ9gYQuPnIUHmJotOVM3YPmWq0HSDTQGvIE8WdDGtHlaemWXQzS6Ra6mdo6lkRL4Slh8EfpKUg4wigWPN0r3GaSXHkkAIs0wgET5OjWqYvTL1QooFFzxPhX1ZTdHcTpcp7CVvRNSVGiTu93qzZloeLF1EwOxsLvQ8hFf9SuWGjeOUYDGh7ktNwrMbeUIV32VkQlqsqQ1HqoKoqjAh2d6Xou7+peaCdxzJOhMf14e/vNiC12p6PfM2oyBY8gR9sMPKd1zgEepWsc+ePSazz3RO+zy9fbc5pJTLZdtswhL0xGhZKuYgYlctRId70DLeyiJHlvEQzEE8KB7QJqULfiB4lgMO84A+DhPeslR4F9Edbm+5P11/ycz4y8kzZQwnt5F4iIOC7HOPRSdGTYTxO53cEcqSfBI/wH7enb6Zt49h8mK4UyYW0fUuKBE7dPAjxC6IxbdabWdu8WefhxUR1oFx6BkdGWLLmj9ZOLMReTwnsJdK5xmoA8wQvV8MMlYiCgBuPj7mYce5s5hpglFxtJdEeDq6P2Mtusvj9uegGeFmCJSn1nbBhJr2r+WxLk/WpDO5lwhggW6V/wdvqcmRvaGHCFspVdzbC2qx104c8i+2wum6kMLHVTGAM9kTy4M5vHtvBELFl/qfldVQ8BK9hUvE9jdUbNQkoiBwFpPt2NNFYvz94CAxqbObxiZ7C1VhKWPH2AMX330wwjiHjh0eshve8e+pjBsDeM4/nTh3PH0P2XNUsomNEDxCQpXG7qngeiMXljTWmyGsLk56SzHFqfCgQX8fLlxv3PzSHXpCkAdymDxnJlcuK6WZIMj0AjQydGVSLgItD0boSI0YfvyDXhrO57OoFuwUU5Enq0do/w+quy8Qt0Qc9Q0afMg0GVUksiDfURVugssB75pqSqdNSrJy3wxM+kSBndgaiKYIakZ1idHkzpiGUshjyAr3V8/N1vW7VGyY2wnoquEclltaRAO6V+O8ymywFWL+/RrPEn4DKy8ul6EmHuryCQh1dfEPk5ZAgYg1K9ecbb2dLwTfMgXIhD/ar0ZfRO5OdwADW376","layer_level":1},{"id":"412f8cb5-54c1-4f32-8966-fa0e5e75bbca","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"性能优化","description":"performance-optimization","prompt":"创建性能优化的详细文档。解释调度系统的性能瓶颈识别和优化策略,包括并发控制、资源管理和内存优化。详细说明异步任务的并发限制、数据库连接池配置和事件循环优化。文档化调度频率调优、批量处理策略和缓存机制。提供性能监控指标、基准测试方法和性能分析工具使用指南。包含实际的性能优化案例、配置参数调整和故障排查技巧。说明如何在高负载情况下保持系统的稳定性和响应性。","parent_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py","gmt_create":"2026-04-22T18:57:25.383759+08:00","gmt_modified":"2026-04-22T19:16:37.81704+08:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3Wm3Q7klXxmeD+JMMoGiSO2oNryWBo1gw9kLkawvxQIW9CASZSiyAjiA/zeT5DwD4S8PDqEsVNE73i6DrCAWvPET3MMPQasVfJTaLge2tk6gbYlx3R6JKZcUoi06jS7okoLDzJAFru3F6zguqySliKZSG/00oFVcDHXlZZc0L7hiq11k1jOD8uBl6n35lAvst/AgFv9MUzrhf43XDwtHiMAxjCAkwKnrWOow44Lwzy5fG3nWKZLSHE3/CUmZ17U3GmEqfG43ai1yloAkMou+sTRIk73sRdXPDze0HhNdNfNXTaOHTxW0gT2TwKGHgG9Jt0Y+1qWq4Nxj/oJTP/hztBLy5SEPndXXqeZTkBaesRTr0adQv49fH0QoFV6D6dxlEOodMiFhvvYd1rvR+HwbQbqU3W5UDVnKfPlMXHsz0a9NPu4aGgk5yevh/s0AP/v2R8mgz3N41lETHxk6Q71f35L04S7u7P6MlorIwKzkeijhFf8sPrChMYX7dwf8dWba+Nwm6fgb+9AbSZ4VczhQInnbiv+GUKiFnezNVSHUUXqTCvRIuhF52jqnOqjPei/1oeS7xAMmB67o3v2so8T17xg94F9FoEl2XuuwA+RFDarVZKACDTPxjt70OXdAoxoERTZ3ivU93OANsuuWx1x0HgFdBj0q6seNC8cbySc3ZuQBWGu1YWMmyIYGL5l6L7CNSmkkl9/pkb1TSfkyM+Hk3VLXy8VIvtgHxGX2OU8yX1nX0DCGS9Yt3dK17lAVH2XF2mo39noQPG2nxjOc+lO/O9cL/CC1Bqzd51YLHapcRLPPbuaMT4ljyLvQ3GMvKHB6c0sjdaKjykN96LhXpO5PAqs3N2edkVKVMC6lg5fTBMZi6B8r4rup3M9CPDs4ehmVYTtnZpt5zKxyXP8QfTO1FfDyNQRpbXj8TyLOwwqEFvZPQlV7Iupj3lpi6crQhtpXBtU9M+vjP31rOrdFpBHXCckE4T9QryVWvQuNDjsc1+tYKLgF6S8ixDQFCHEAfzctdMM3iiLCeBy1szBZEZTE+OS0ERSbgqusmZBkz3ouKp6suUgXLJp3Kystu+dAVWhA6BAD2WHT76h+Hbazixj8F2qAoxmUb+P8Z7u0grbWJksg6u","layer_level":1},{"id":"40ac97e8-7ef0-4198-82d7-d2e332be9d34","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"测试最佳实践","description":"test-best-practices","prompt":"创建GEO项目测试最佳实践的指导文档。详细说明测试代码的编写规范,包括命名约定、测试结构和注释标准。文档化测试覆盖率的要求和测量方法,包括行覆盖率、分支覆盖率和功能覆盖率。说明持续集成配置,包括GitHub Actions或类似CI/CD工具的设置。提供测试调试技巧,包括pytest调试选项、日志配置和错误排查方法。包含测试环境管理、测试数据管理和测试报告生成的实践指南。","parent_id":"fc6f24c3-594e-4153-854f-19250834eeb1","order":2,"progress_status":"completed","dependent_files":"tests/conftest.py,.pytest_cache/,backend/app/config.py","gmt_create":"2026-04-22T18:57:25.616954+08:00","gmt_modified":"2026-04-22T19:17:48.81542+08:00","raw_data":"WikiEncrypted:3lrOgsvw7LaJXRS/Bz00iEsb4RzJUAxxpmqaBblS/51b52WVRQtf4YGBQ9MC2MYcYNyKxRGZljd03HKmm078aoRU+suxjG3HIqwkvM6ruyPxwlLdBEn6ogbrhm8eOKuGWjiEso+PrOqSXW0boT4qGE+/L4MkPiyeOB9YnDB49/ByvDHsjeesTQqGwpa9FmIQtVqpqDZA3Sx+x8TB+MSqT5PMZ4egRgCW1ODcidZrTriWvseFNQDFLzo8g2H/HF5CFLcVsZVK+kWI7b7oWLmNlIKz2SyVJuYqvCblPzw+/773Wv4RVHYdK/pxISCon/L1KjPyfZjddr5sDjJO7rNFbBshPxUIQhtXnnAEqLOpzZwHm2a0bA3vSR42bZZoSAY0v3aZxXQ5IvxNT/aNAmiFzd4SkTlz0okDXnBsArnOUpLLRfjLhxt5ueRUi9Dl2edsdycd6XznT6/oAUHTf05zhhKC6JR1OsKiFQyoo0il7LYjDxXJM0dZycDlENYwZ3Bd/82Qr+7VNmgpLdnB/7z9DPG9iou6TIpztKrdSRYqWBcl75qs2L/R2Sy6MOyfSwALTRUi5udf8sNlsHOk5y2qY0h7vd1GzYwtxKQ63ypJLL/8fAcPKmH3FCwKvrN3zuEu0Meyq+y2v8eYeXNozeOa2zum6fI5sw7hnzX9Jqy7fyQD2yBFqyylQ1ZW3nwFd9liZLnWfm7zbLDlqSgzGYGxvNIe0X2rhwsthMZTLEXOZVDW1/NqHg2E9qXOfg7XhQRHKZz6Wu8eZ6MGyCvq6ft2SJI2vltHD0M4somneHGSMo4jKY8rMeGl7qkW1V7aaurBnh0xp6cOJ25IdbN4VEDYm1Oj5nlM4wnEQzWiVyEqA+3oU2k2k9Plm/xs6g846/lBJxHL9ztsKmm0BnrUFR1ttgTVRAFvHpfkmSgLGGB/9824DJpxXMiWnExCaZzWbFYPhXnDF6Kh3SB6P3NyVwVdC9/pkf4/UQ4Em3rvbVuWICjGSScoDtOu5MrHDaUSbtN/XtqOptA1ApGbnTSKxOm0KAck4ApFPdk6aRLdC4eRf9XWsWUaOFjkqAoU0Kp035pHaGrCrx4KmgoKBNFNbS55CA==","layer_level":1},{"id":"41a414d2-e13a-497c-8a03-212624dbf5fe","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用数据接口","description":"citations-api","prompt":"创建引用数据查询和分析的完整API文档。详细记录引用数据的查询接口、统计分析功能和上下文提取机制。说明引用检测结果的数据结构、置信度评分和品牌识别算法。文档化引用趋势分析、平台对比和竞争品牌识别的API端点。包含数据过滤、排序和分页查询的参数说明。提供引用数据可视化和报告生成功能的接口使用指南。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":2,"progress_status":"completed","dependent_files":"backend/app/api/citations.py,backend/app/schemas/citation.py,backend/app/models/citation_record.py","gmt_create":"2026-04-22T18:57:37.836961+08:00","gmt_modified":"2026-04-22T19:18:18.055339+08:00","raw_data":"WikiEncrypted:qByx+WzXalKNnda2aYUs+Mi+kQm14b3+m7dy1helFRbYWzECOnPEzHl0ufCZlQvKjQqSxHIwqppPXSdvXYc/8Z7buvJqBV/Q/faiP/SBsAH3RrfF2Ppti6QanNvcAtBLcojqJkmfYWFej1OYdagzBcSAu0xIIA7qBG1LwkdNG8crxSwebM8is42SnI+aRvlbF4UdAqHHPdfUvnzs7zIODnildIoR60AvLFeNEWO4prQkFyS16p1YH96SousrFgBu2YZZYrNOOhDXyrRoW3TE6990oaIi3Xe0B7jFtC4pce8JamwzT8B33FAJ6utCOBMUkFKq6l0kD5rN2owZaBtGc4Q66Xcb62y3arqrvxcgE1ox1nAp2D9pNqRy3W1ePW2fWZk4+3co4z2+ANQ1JO8q5eAFI6Q6zG7hM4rvNlL07iD+hZeqd5+vGw0KmjkN4VMqJC5ypFf5UCF4qHgB6TS9ToQUAWk6HWlwBR1DVpCcK1kyGcunn6EiivJyjJLRYUXI66AmajxIzRHtyhxBnA5Q4hZNgr40jHMoUbWHmiQTQr7Ca4/VDS2V5FWlm6K1fN8xWRIUCI3VtH0A/wG+QBnJmF5YeqDZ37Nx9vkiaO+hutXsGHsjwj8+IZO/gpn6UT6QpOGaeqGl37HW+lMZSRUqFFaLg7jxlzSa3IliOyZI7N6xjFFFTrLV1ShVsDcWDg4eXL2IjJ7QfXjmD0vq5mH8mkZK6HbhpNH5kFXDuMYWPIHAXUk39ttNvut9r22RLpkXYWtxE7XoqXW+k+Edmt2eNvZImq/e7mUwa82Cae86WiRtz7B7TJeOf96EvN6EQBg8E8KT5Ckd1exHhFtySkw3tYfChBZfD75zY7tUcZcC+McO1Kf0ORqTZtnNjVnot7wirysiS6WKQ3O2L0CeBUUV7DlmFd8xAgJ8YhtHJKulJ2B0yCCswfb+PR6u9GKFVK1EcspZe5BsT22vlhQyAJxlqiAi9xRk+XaCWoUT5ymT+KMOXdLoB4EvD2ftgXy5GMxZIK2q1QtLAYEu7nOBsq2aNAg9i9IsVJ6OlCN7VMzDinzkoC1IAWKxKE67ZeLq/VfPmCqLKGl0z1JfkfC/kU8KFA==","layer_level":1},{"id":"2f7fa0ab-cd3d-4f45-a1c1-389d5a0c2561","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发工具","description":"development-tools","prompt":"创建GEO项目开发工具使用文档。详细说明IDE配置和推荐插件,包括VS Code配置、Python和TypeScript扩展。文档化调试工具的使用方法,包括断点调试、日志分析和性能分析。说明开发辅助工具,如API测试工具、数据库管理工具和Docker容器管理。提供命令行工具和脚本的使用指南。包含开发环境的优化配置和故障排查方法。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":2,"progress_status":"completed","dependent_files":"frontend/tsconfig.json,frontend/tailwind.config.ts,backend/requirements.txt,frontend/.eslintrc.json","gmt_create":"2026-04-22T18:57:39.374817+08:00","gmt_modified":"2026-04-22T19:17:43.353691+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9CzRj7niAsR4WPU/tuSJ2vBrZ49vjzLlsqusYQAR0/FVC/Mfa58hrglY/tUSn8LBYDGZlVr/UyLd9/U09SEPTjzLPzOXWOffceGYhaM8E9Cx6c+FHZRQ0fYUDQXxWM6dQF6WQbUmiZISlUpgtOkT5wX0oc/n1YeDUxEpgiCWnOdIBH6SDoRDdGUFrWdqF66bEdplp0Yy3VYVBKKwUy1XVXtLbdv1T5/0TVJO7EtkHdoheIwKCPIYHsaJqBv4U8cMNegSJ1Ti8bsgUakd6FM/X0ybfTay+IyTIqYXj/dS0tWMm22zjLqYmw59+s8gJ7AlgwXhqYhM5Ycwh/PNrDHHFbgQdt45DjAaMWjrjXrbIvM+kXuSiwxW0dEvQtouckPTVohVcRWEPbg2o02/8Y5DzmxpceOC7KgybfaaCQeJHbg9C91itVc+0NvorhivJt105EYs1ndSOla9hoFppywKIbIM61cvqgHjsJF5DrN1pneGmTtYxijl3J/QpJHn5QuIBR8ugoHdJ3EVjUR38vQReVBeDxI/VMe8k/l3EI/Zk7paXexGeTrJmmnZI1I6WbPN1TPS4nLFZWwkA5ZA7wMkdHiHdnt/FZGccFyq8X9Okog2xv6uqH6Kwz3hseWlrSygNPzDr0cFj2EQqDH7+xZDEkAvTuFLHn+HzUfBv0vfZFa/FRg+5/agC9EcMHM+75jEvtSeeHXHOLpuuFcyOcZ0IQP99QdzSEsLaISCINs5SKkzKAMQnJv4PEDo/vFAKBulCSqjXmLeyhcKmCGqafN7IMWUWF5pmZuXe7wL1F6n+x3+RvScmsWND74hQhn0/Sn8kpFHJ5xV/5t0GDZxWybDFRRuFC8oImKyB+6h8CstsERuFeiIjMv2TS5lz8+eb1/yCUkGO9X5mUpJZXfZ+0vu2SkEN3WR92tM5Di/78rDlulwZ4oykT8NzYMTzpX4WlgUfazNKLyIhSoFZcWUyOFcU8IWCoOdrBFn5CSpe0VXbOlP3pAU1Lz6Y016JUHo1t1YE9xU/m7OTxhMexA8jCoSswgGT+Cjs9u+KP1ji2RSyZHQ6","layer_level":1},{"id":"2713d5c6-c6b0-4a38-83f6-56940c2bf695","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"监控与日志管理","description":"monitoring-logging","prompt":"创建GEO项目监控与日志管理的完整方案。说明应用健康检查的实现,包括服务可用性监控、响应时间监控和错误率统计。文档化日志收集和管理策略,包括结构化日志格式、日志轮转和存储策略。详细解释错误追踪机制,包括异常捕获、堆栈跟踪和告警通知。提供性能监控指标,包括CPU使用率、内存占用、数据库连接数和API响应时间。说明监控工具的选择和配置,如Prometheus、Grafana或云监控服务。包含日志分析和故障诊断的最佳实践。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":2,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/app/main.py,frontend/app/layout.tsx","gmt_create":"2026-04-22T18:57:40.355514+08:00","gmt_modified":"2026-04-22T19:18:41.773778+08:00","raw_data":"WikiEncrypted:HL3VqGjXq8A3aGeLxAjVPg+lnGgkT5PNghnzp51sgLDjuJwvzPZp6KDp64sXTqk/PvlUYRCEe6pgM8WKdtus6ThN6y8bzS650UmrWXRgW48k0tbm2PEPd8NIqpzEYwRwyuzLECVz8rV+mgvy+OHzvrt+wEQeT7z1uljirnxeLZWJjIrFBr8Q1T8WQ9InM3Ttnvm7OYO+YH2Mqi6IC38bW7w4WGqApS+Byn7/ZrJhR3B/XWh91FPwq0GRUJ9cqrNuIcYtnWAfVIHWOe3iET8Jw+Un5x7ZRepcJlINGIIMBE2hO7UsbC/K3z8rkz7mx6uoPTPpxkKkgoQQ1OAsShE/wpHpRYSOJEnV26GFo4bXBTk6xJYw7daKnJVIYDSqSrtJQI4yPlTR0OtJescXSLobznoVSBo+L+PU/nRvotp5KzX0SUpbkqNzGychqcBuJhpS1eaEP0cTBjvjC4MJ5Lsye51X6aOdYYC7tBWHxtgBO93tkpcIRlHk8Dfmzh8nKcD0rPHYGnaeFpzXgGH7ZfabAwxiMhej6OXWsfnbHGg4gheWhXfokxCMKkFnzrsYcuFtB0BqUeadjP5LArbJJGeyVEZovmPxtzQ5z/ayxJs+oyc0oH2SMXCFtIQv2h03ZSOCkohVRs2oTJnMI2p41dY59B5qiSOp+0qwxTWL9NnpqM2gjlLZhcgwF//R7ag4ndECWejInOcA9Ayvx6cPAuH6uEoFTcUOCLaOZ/u9T8890S5KHS7PcNM8dEewoFviz/mRiernAhd08l7a9lR6zck842Ywi5H8+fuuHyt64Pwco/+52MhD01pkK+HWSR0EqPc8URlkOKjQSW0jd8E/9ow54aZA0+1Vto3d+Lqi/tAOlhRF34rIJgTEN3f/udCEVycON9KNtssYzZVNPdvTkvzPYdUHIcnYmz3jbQhnYnrYvuaWNvO0cPISLZI9szxLP8IhmUc9xT4U3OvoRfFka8TABGicEUAF6vpH6H2rCqnWdBydaTpRTa3VAR7QJ+M0aPlzeKov93eljMa/djYoQo+w8Rm3A9vGmGXJKfWdZobh+fQgc38Z/0yRCHnIPnY8o6CDBfwbANfjDRpjyVkqWq1cuqYNnMul/jpzDS9vMSbMnefISRuF0kH8XS5C7pIB+WFn1vxeYFBYED7ZI4FD9pxxS6GWGcYOXEoFcqtR+lEiMdj0Q09jo1nEuMKJbPQre/RG08O0boFCzF9KOSnS0UA09/82vFQyQZKHNwpz7OkZZa2cX5X1L/pdsDlDRoIdp2lzyAEOidStaIWywEj11EYVNbG7sK562p96Sr15ueIXP0s=","layer_level":1},{"id":"c8a468af-2982-4d9c-82c0-313b5d2ee89c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"第三方集成","description":"third-party-integration","prompt":"创建GEO项目第三方集成的详细指南。说明新AI平台接入的完整流程,包括适配器接口实现、平台认证配置和查询逻辑适配。详细介绍新数据库支持的集成方法,包括SQLAlchemy模型扩展、迁移脚本编写和连接配置。文档化新认证方式的集成步骤,包括OAuth提供商配置、JWT令牌处理和权限系统扩展。提供插件系统的使用指南,包括插件注册机制、生命周期管理和错误处理。包含具体的集成示例和常见问题解决方案。","parent_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","order":2,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py,backend/app/services/auth.py","gmt_create":"2026-04-22T18:57:48.68499+08:00","gmt_modified":"2026-04-22T19:19:17.361215+08:00","raw_data":"WikiEncrypted:WxCGFGSl9zR6IDeUdkqKNACFcGLyx5HNn0UQzHtkOJVoVN2BLrMtPbbNkfhYYzEQGaeK3o4fBODff6YTXKxAV6HYhCHjmdXJqBaBsEPBB205lzDAllfBZL4/6ljz+/HZSgaWAxPECD1m2GUFvjlKHTSXEb0x5iVOg9R3VDjYQgKl1SF3S/AuJj7QBbGiwmkyPrqO8+NXDlKH7pI3G6me5ulZrK6M85KSH8nVAnqY/Mvjc6UGQJBwS1QyKJVzzK2JwKGhQSSLemxD887b22bSe7q1IEDRYcpqkbfyICB0zF1Gg1h/cAfQgzjiG0+MQiC5CF3QwkFteFbN4KZDEjCTcbIR+HqI+yCs8Wue/MwdoTYQQKpR9FyClONZn5T/UqHQaVT8SemYF0QC/kawyEZFH5Tkj/6RwS+taTWw1fx2QC69xQlW04ManahzsBDwfz2W4RkufM3ZfW8HAN7SorY7oYr1Vam2p2u/93jzHmi7PO/Y6VphQNACzUlfRYsPALVBkiqpN4TIiicrjOvhgATUxqpku2MrAtbXTkiuiiQBamK/XrF4JNlh+79VGoHKWniah1nvo+dzl7jll4j0woKwWKIzmfPXLS68HekW9h5BH9SUeuyAEW/pvnGAUw8Od3CgsEmap86k42Tg9pRZC/sT9bCWUbjO6ijJ9IPAgWE6bkLCu68L2BD1yKE3gfLg0hJmELn79lHaFCUc5jlRdJ4HEsalAFGS62beLGkude98NvSY5pQoO9jbTj3Da8t6Yj8p97WtE73vmWW9Pu/YyAtxJH7Cdwvv9mbvLYVnLzUWGwsaiaXmDJiqfSHiOrHQNyonHQa8N/LYrbB8qBSUmLyBUhgI1YfYMa+zNfCaeHvRLlmVZpui5MOegWen1Z61WhPc6WoFYHyFAdgS7k21cC9jVay3u87SjSzooFT3MJjN+yMIjrQ5U+tVFbiBQK7IGPLFHRmvFBrBwSFVBI5VnCxn4piz7VBp7mm3e6N3CJUKShQWQT9tmUIRXLmmzsKTit/kRAUrycFjixIK8Hm4kSwtVBREbX3opXE6clXKGVB0bpSDUzB8Ae7wOPE8Gqo/ewy3kh2mdNnvI3+MfOOgPc+Ovqu3KGFBH/MYKl2xIUGdYtEHfHRCIFFVVknX8+Q+tfbkmo/Tw+kJfq67IQO6VT1WjP/q1G3rOhp0Ah5h1wmxVfdIaHSUOT03yQTBm/tqCXlgUW7rZbTc2wF0zdUUWleQoq9pc14c0F2SNFCSaQNLhxvfeC2aH8O9nuZi+kVb+GVV4vWcxcz/7dfTkXpogDwy6uqVHySe/TAn04uWlCabYSrA3ahnl0VpBmalBU1dtaTG5apgcCJ9PULyHWKf+iW0vle9pOVgZQ4oUv0vXxDpZQkO1SOBCfKG20swUEItxbAxIVoMowR52maIRnCKh3g18NF3JUZX2ptDny7A2gmsYWU=","layer_level":1},{"id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"前端系统架构","description":"frontend-architecture","prompt":"创建GEO前端系统的架构文档。详细说明基于Next.js 14的应用架构设计,包括App Router的页面组织、服务器组件和客户端组件的混合使用模式。文档化认证系统的前端实现,包括NextAuth.js集成、会话管理和路由保护机制。解释UI组件库的设计理念、组件复用策略和样式系统配置。说明数据获取策略、状态管理和错误处理机制。包含响应式设计、可访问性支持和性能优化方案。提供前端开发的最佳实践和代码组织规范。","order":3,"progress_status":"completed","dependent_files":"frontend/app/(auth)/forgot-password/page.tsx,frontend/app/(auth)/reset-password/page.tsx,frontend/app/(auth)/verify-email/page.tsx,frontend/app/(dashboard)/dashboard/admin/page.tsx,frontend/app/(dashboard)/dashboard/settings/page.tsx,frontend/lib/api.ts,frontend/lib/auth.ts,frontend/app/layout.tsx,frontend/components/,frontend/next.config.mjs,frontend/tailwind.config.ts","gmt_create":"2026-04-22T18:56:47.082624+08:00","gmt_modified":"2026-05-23T15:22:58.592252+08:00","raw_data":"WikiEncrypted:caZUAHH9Plb/hKq4968GAlxdfXo1OZ/T5bAEX+yDDFnwmkOIiMXkaH0ZIHauIC0wfdpuxtoUKmX43kiFQyTbPAtTiYEiDR6Tc0QitLHu+/t2EuUEwUv7xUQwEV4sW//IvEpbtqaL5pRUagOGJPFa99C4e52Nk9vZW1Kx2qPB4qhq5J3Yu0nD02qlXghyoNL0NJHwuCxv7EahSsg/DYFr7sH0a3S5ETkZqxe96N44pBOsBHzuIrVBbRVxAXK34mDFp06Mg6X+bx/FzcoakGVIQ2IA1/sQmnUSpwDxGqn3UvGx6xVk7KBPYjKthY6SgyELy3XXUvLqYYrMzXJIpLCJenAAXTvXsseT+uR3pZTNb8c8t6DMq8wmc/nSYKx0/o0eWgxwGCW7U/hzreWW7EG1vT6Wvls/+9iCH022pB7CS06DX6cdGv+wSYp0wvWU6q7c+JXjhvI3Tz9BouXfgOipLBXfzo1GPVD211oTxUEOthWdIsJ/xrK33RKfN0edxP363h7CV1jAUHsZPO0hLP6ZZRpC7kDuFps/PTY5k+15rMjKsA3p4d2gO79r8IJ+nN0PDwK0ncShwqlQ74k0G1vS9tFBnH9lhq/1UdozkYQsNxDa5+YN28fNiYVXPNLS7cqj61w7y6GbW1rL7QuJy4pTuPCl1lJrFqDN0xi2a3KM4l00HZ9qbBQPyC2zF3cSmK/bbd8R4rrwbXzSJKOHyb/7Uhx0mbARihsrOJ9s68hspwmIvznUBYnF+y0y27DfTemQ5/UpNlT/WzU1zwIk8xA0KX1bdYS+fdH/CRZH7axSnG0WcjwloudpfvLbXWzUGypiGhAvZSnTEATuWW/rp86QszDvxQXgB7N1OSJFUuOUE6vxX1nwr/YGFsk75EmWWRT/5l3BoNW5rsNqeaOLPCUIe7RFj4U2hiWsrhjyXXyMpm/dpjmAIgPnYGeaPQ6+3ndGg1ooLn2zeijt4pY+yaM0JWp5giDt8jr7YhAcLRW7ojqK8IAhk51K/khU5x0HFI/rUYBS3k7j6V0pkUQYziBrVpYavetotm9w6yw1tQrB4G9Pkh4/NGGjdJ9ZtPdoAhxwq/vFKRixUOxtOzPW+gjiBJx5aBFLlGh4OeNikZu8dkvi4o72oyn86HfoxqjayhfyKFjnAhLuk7u4H7UAw5+imyWFIuT10HE4ku7WESF+jU2I9KtomZm4+j88sEG1m/c2PAvqMWR/TbzgZdogHbPk99qTZ9/Gxa8sAEqijUgFeXZHhD6fT+Owl9unUBxIhv0T7zY7KJFcowSL9eOirUOnlOuZcqFUdFT1pE9B9MpnS+aAo4H68NaI+k/JsFne7qyToLEjzezrMiWggu4qPvxqH/1YvhZKbm99SeiGQ/fSWhVKN3kcpby3wdWau5I3Eg0DApusN4Z+nnZY3kwY8CbBAHbv6lx5XVCfA2tw9MHDPpiVaxmBdA5fWmu4HSnt0v0Vrb5r3R/ZVl9ERMQUne52UjUl3II1fMML4ZrZzOexAOnQ1WJ+zHyQjGkcBkU6xS0R8uOhu5xA3obBmqzzET2RslAFXre9XhksI9E/qhzxB5abhiKMV8vs5G8GNJ1rQ0nQq0M/BbL6Rz6is7oJWTf8pL91hYykA0bUMRKq60t6umP9XKaKzF31+7PIs18PRJQ8Rzji9jXk2GJ9TpT4sc9ty9XTBQg6Je/vhkN2SlkNbxA0RoiWRMA5QxA4fnjOxWOFdP7X8ugdY1SIyFHmAR+TiEiGbH6qjNqMQD+PTmmi+1s="},{"id":"9eee7fab-6cd9-4ef3-9415-2f8137f1d199","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据模型设计","description":"data-models","prompt":"为GEO数据模型创建全面的设计文档。详细解释SQLAlchemy ORM模型定义,包括类结构设计、字段类型选择和关系映射。文档化用户模型(User),包括用户属性、权限字段和关联关系。说明查询模型(Query)的设计,包括查询参数、执行状态和时间戳字段。解释引用记录模型(CitationRecord),包括品牌信息、置信度评分和上下文数据。详细描述查询任务模型(QueryTask),包括调度状态、执行历史和错误信息。包含订阅模型(Subscription)的设计和用途。提供模型间关系图、索引策略和性能优化建议。说明数据验证规则和业务约束。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":3,"progress_status":"completed","dependent_files":"backend/app/models/user.py,backend/app/models/query.py,backend/app/models/citation_record.py,backend/app/models/query_task.py,backend/app/models/subscription.py","gmt_create":"2026-04-22T18:57:02.317816+08:00","gmt_modified":"2026-04-22T19:19:19.281909+08:00","raw_data":"WikiEncrypted:klcgW2PbPxJambbKMzvFtzxL0nPpsuPMPxr5hj83lS7k/WfePQWgQNKbEysjyVqFS8lXlJL069Py2sSf8yXxHJzOE+5qAqcKClz711a5h2iXkF0al3mIdEvPGsZtmu7Tz91D+nYN6P20/dGDD6jbfsmIRXLEv3fpccmaTd5XoNj9Y/QT7a0xg+LkG6A8bzQONV8mQsFJZMj512PXdrzG8bSiiAdWa7PEbotJVKJRklAdLNFr4FCsLXLsdS/G2RlAo97zi5J4mpx26Q7SGM1kx14TxsQYatCIUYP+iZ14NDPPPp8tQ+HGPLEonVbYiRiktzJo8Iaqbcsh59qHBoGZBndXEwalDBXzD3sIbYrhxlOU509HDe43hiq+M5eC2SEeTfGdYZ412t/aAJFPEfq3dRl0wa6Oiw4t4rox0s/f+rCg9Sr5yX/vsXrADGwowbhqt/EdTudfsdha7MXN3Kn9e9TckQ+HOqdgqW3+RnY3B08ijVPZchn/Y7XZvx8GujUHSuM3x7EDAXegqkPwkfR+hl4yb4BuuY5AC17g3hvn9yDvBN3m/Ky7mJ4Q9qvXfFaUqDE/FxwPWjugAnVOgAmWns1elVLUS/2nol2BUAuyt1w821y7+N79TkQ07amTWILYvO7I/5v6hStaHk5+ftwpaWSLofuk3Nwbuab8ULq6lj/Tz3uWkEg5/nIIYGVDSN2y9JKgkNta0J9Y4C25DpKnPb2HPfbnD/315IEyxKddS9DpOHC92uT3Ad5v/X0LgVsefqUUep4D2mVUeevDE2o9NuUqYyWYu16AL2UaQOWH86Q97+Accmt37g5580pjdVyzcgVL6Lat1P4W42Nk0vOIncIdM8Bt+iWUIOjmIWDK6nUytRrluJ6RAGeewol6Eb8eMy65WkJ8SsDWFj936G3imq6uoKEsmn9kHznKIfsvt/p4IAv+IbkliuuV7/VNQdN4jgfgKyRp8b4aQd35Qrv1ypuTdf2HQS3w/t3nb8hBriaZZc8a93LekZYaGpvrws/aq3ESXMU+csJKfWhEGhH4VT4cjy6j+jHgihUuUWhO1X/Kpm8iseqreG85CZeU9woTd/nPIayXO14kUEfNVL1ih3p7GtsFGDYpr4EcPU7JpPp61gLhfdpHydKVDLW4eaaCuTR4REP2Vs2BxiwN8GCpJcCbpPeF52n9qB1DE3uIVBITabqC0jiIHeVfb8caysKpddelqqLNn4GGL7BeUFq4RKhlVTmCGuBRWABBDEhDRHXsScje6Av8bOxE/QFVlZmFE8EkDM/WhG9hB5BQ+8u4pKPxsL3/n7xyMyrBnO2n+nTEGscgwlEnpxknYpBTrtZQgU5YB8KRGG+VnvSlbM95vPmdiXS5y7JM9ftKUbdxgnxOVrM2ydbK+5IGvaNB27szvHBbvqtxiY8lXfLRhMYcQEIcD0AM4Xl1qH90xIrHF3lHogdPgwXR/UWGRDWDXKVUEXGRLQHTlRTCJ2oRBGig4FvIztUbBVqouwtJBqoGXoMET7JbuNkxdHs7pfsL8sV5FksVAyNxvV7rRG5QAMaIvUMdDT+XAhtcrNagCHcb53sPxuz9ldlj9adP1H+FxOw7","layer_level":1},{"id":"d9e45b2a-6443-4a9b-8ed3-4c3c04773772","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"UI组件库","description":"ui-component-library","prompt":"创建UI组件库的详细文档。说明基于Radix UI的组件设计原则、可访问性和一致性保证。文档化基础UI组件的功能特性、属性配置和使用示例。解释组件的样式定制、主题支持和响应式行为。说明组件组合模式、状态管理和事件处理机制。包含组件的无障碍支持、键盘导航和屏幕阅读器兼容性。提供组件使用规范、最佳实践和自定义扩展指南。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":3,"progress_status":"completed","dependent_files":"frontend/components/ui/button.tsx,frontend/components/ui/input.tsx,frontend/components/ui/select.tsx,frontend/components/ui/dialog.tsx,frontend/components/ui/table.tsx,frontend/components/ui/card.tsx,frontend/components/ui/tabs.tsx,frontend/components/ui/dropdown-menu.tsx","gmt_create":"2026-04-22T18:57:04.216865+08:00","gmt_modified":"2026-04-23T15:22:23.573963+08:00","raw_data":"WikiEncrypted:mOhGqVhKXtp0S+QeVzok74WypWJ7klGHRH+KdUSnimLTYfyBjBDRPAzXT+gcOXfQVvcrNlnW0hq9eH7zZFCqkZsBgmYKEU+paWYmItwEmPFSm8j97/vwvs9ugP1aTV0WKgu1SgAg9UjbHTpC/aH+MMWl8IEcuuqWfI5XbGaUR87WXcEDmdrb3wUoUJRDu/cGjCf/fvmakwSGbuyVnUxAKC0b89qWigFSx7MqlY8I3hXqAtSNiskE28duoh2j488f5d1qN4KsTvxvRe26wRYqlD4qzi7WQGBZQUoeoyVRA8PrJFhxeH6clcVYO0kStx160hPPrlpF93ul/lDmdVwrTZfpWh5RRY5u02+lOo2Vcl73yz1ixYzt/OXYaenA0jUTFVdPJ2OcTZGDQV7xMOPFPX3iFNKxuHY9aks8ARFEUs2BtyH+KlyKfPdKqDAlklqIVzP4MH2E6uDcvYMSORu7S1T+53+R9br9Cfu1PSZkuVdmHNqUuKSLA7pMI1QiVYXtwk2GYmRGYUH7geeQddC61wxpCG1rXcVzBMSS8LxtR3SSj/9VQ0v2YyrqKzRh44BKjm+ojKbz8rNcf69UZ5Fu4dU5kGqXy/XWbFbSmoUmrWXnZ2zWPhMIgHAIsTe/iX6JC5Q3L70XVbXk4S/ffk/sKKtdV7XrQVmVPhSquUc7x1RcfMyLVgxyoFEOwwk9LfQIPE9n16lNCvDWX3UuK2TDcqDbwJQ/FMmjaZDilRQFs+8MA5I/UUtC5CyzoOiLRXvPqQQiqXjBs6jefxc0cpGAJwUkaISOvQum6WtKWK3y1CphRMH2hkB4bF7NgyOm8z/0JXMSpcPR8nMUY4M8pW9MZYQEL76sWcQAD/oiWlgAUccgiRPnCiU0Xz7/MplIj0jTRwXXzc8arUGle1DmiJFEVmztGZOQsIGDqSwKGG5XHEdLyKe2hWHqBGRWkqZrsBqS8KrFUWk5lefvdDZvi8ci+S4wdZQX8IDx0siYw5cfdMlilWuaptf6qf/qEVaIO5DX+MMGPmGBz7jnyaQfo2QWlpybbe/uLTvhZTe75uY9Revd+DPo+zgmDUmGj4hSliiZx0smUxDq2wMZmKLx3x7N8m1jdGgqT+LVQAhdUcmE1Qx3W7e51K9wB4PN3L8k8bDewzE25kuU6a7QpDLdn5lSa8n0E0Yug9cp3wgllhZVFVmyjVr/oC3c0I5z3elvtrYub9jPeRtR4AmW7w2RPcUt/8f7j8aMH/1lUBQk+GL6OhXAEnzmav2Q2smdsQqWS4cVj/FV1lrfoV+peL4fo5CxYMv/ZJSvbJaFSpBOPzf09qJBxUptVeosUyAUDv7YsJdUo02ZE8B3ZXZGcpKGKSRiBeLQKjuqkck1rBeJK4PnEEXZ5vtz2ONe8tddj5qna0a3","layer_level":1},{"id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"核心功能","description":"core-features","prompt":"为GEO项目创建核心功能概览文档。详细介绍GEO平台的主要功能模块,包括用户认证与权限管理、智能查询任务管理、品牌引用检测引擎、多AI平台数据集成、数据分析与可视化、报告导出等。解释每个功能模块的核心价值和使用场景,如查询任务的定时执行、引用检测的置信度评分、趋势图表的数据可视化等。说明功能模块之间的协作关系和数据流转。提供典型使用流程和操作示例,帮助用户快速理解如何使用各项功能。面向不同角色用户提供功能介绍,如管理员的系统管理、研究人员的查询分析等。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":3,"progress_status":"completed","dependent_files":"backend/app/api/queries.py,backend/app/api/citations.py,backend/app/workers/citation_engine.py,frontend/app/(dashboard)/dashboard/page.tsx","gmt_create":"2026-04-22T18:57:13.330097+08:00","gmt_modified":"2026-05-23T15:23:21.993776+08:00","raw_data":"WikiEncrypted:T7sUiJOX3kDqyMLpD1WxBIoa4LuUt0BbmRUUbwQKSxGYrSupCPI/c9cAW4Z1FJ3a1KfzsqdN2t6YAo/gosyxBdAnQrG5i041HZhmJKdZMwMbHjgD/RwvogODN6jShAuCXS1wYxG016ckUnMfO1cR27Jpvg5/1VIs4Z0RBM7gHaNEutGfgMGN/I67TUKhPXC/gwiBILP7Y1VZXpfd9oYmAeRE4Hsw3Nu7OTZqs2gFIjiQwx55aB0rjkS10JeQsgk9pIlNX/9lDYZMl6xYjsBJQ8lxF2zGBk1tLhlpPhnAn9HdhyZoPni3elvWwv6UW9GLHlQXTtW9AGhQGm4JhCw9U4fboYKFJraw2Nv4bUmzUZEwcrJifeC8ncf/VMdXqwmsMncVFJIOusFzAYsDMYvPgZwYitYWE0ELl0m+VrGfg3gMEyvuer6DFPFXJYr3zn/8bxxUDtay+rbQW4gDLy2l12BDDD6lmuvJbof4HWkiX2EylGcHKkqDjfiyJefn/gr1vqUR5Hh+6/xhXEb1dg+EWe4d1AxDLjIZVYuxvN6CNIcrihYs4wM2Zz1cE5GDUXsjvGBhLizJl+zSzLw1eEKqursiPFj4ZLuMpZtZPoHgaqMEE4jc5YBNU/dZ5vox5QB/9JxbSziQf8n9RNHAZieiKS1QEsQo41P3/53Ax4xwvzAoamtIo2Gxz9b17VFPCXFNArl+QzjdgDAhu9WTDTjuTjTsc/pt/WGUtc+PZdAtBeuLYJpCW8hGHB87/xEQ7/IKjcYB7lX8YTVK/Io9szc+APABgA1I0DfiTZ2G9tR0V32MhOPGfFvq0gqsiBzO3kmgrBHVxP3RR4Th9JKzzd+O7DET9G2a/04uAfqk1j/uvmxG7k/o93XQKWQ7AVieZrJnTDajI6xewy3dXCmYmf2IfnwEwctUJ5qEtWAdHH3PXTpZdN6haMsFKlsEGTt40ZSzELm7MWmMnlTiTwYQ/BSp9B8cYVauEYpqt8gEDQVJzH2mvFZFI8KJ5wAUo/W5jrP62ijIg/TjqVeyPVSbipePWw+mCi4MLJy7ZaQ5I5YFk/SjqNZyKvOj2WMHZvUF4bBbqPh6YUokCLivlOKRRPrIYHbRgsWmIbinQeyYHTNiaHiujGWxIYL1WjkFbe1BUCv9q4gpPjVs7grIYbPxPREC5yu5FrCu7UXmFRBxpZ5KR3gZRlsU6TgNQtwUUYgIYsQeGclv2BeMBD9i5fQVaSGeuXeCPnHFUr50RpSUObWVX/y4C6Djns5ABd794m/HYgNsw81dRog2rHKJmLr3c0K2zHKTsp3EPRH0yPo6fLQjUiWNPrU4js9xwwPgc6OCWpnIUQtgdYfoZxuH9D5C3wNAwdMlPO4VBZS/r06+YI9GMJgxvvcPnfsndwOEn8Wp+Jbr2rU1cuPNIqYZRZpxiszhc9t4Dl5neRb0JdpJJWFzrtOxkkr2K6FdyNDxeezvgjNYIUkMHTk9ayOYfhZjXrKrhA==","layer_level":1},{"id":"f210509a-2381-46fe-8c22-0ed768e6ca70","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库迁移","description":"database-migration","prompt":"创建GEO项目数据库迁移文档。详细说明Alembic迁移框架的配置和使用,包括迁移脚本的生成、版本管理和数据库升级策略。文档化初始迁移脚本的实现,包括表创建、索引建立和约束添加。解释迁移命令的使用方法,如upgrade、downgrade和autogenerate功能。说明迁移过程中的数据保护、回滚机制和版本控制。包含生产环境迁移的最佳实践和风险控制措施。","parent_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","order":3,"progress_status":"completed","dependent_files":"backend/alembic/,backend/alembic.ini,backend/alembic/versions/488d0bd5ab01_initial_migration.py","gmt_create":"2026-04-22T18:57:14.161329+08:00","gmt_modified":"2026-04-22T19:20:15.066432+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkH9ryxDJ0NroguMukGrnBDccbI7FhPTNCbxlVVf68ZQ7vvUzAxXQ43tY1R33KAEW91uvBjnohUVl7Q+D/Ap3SUnHDpWQWBM8qdBbgPmANzeAhinu9R6LqaM1BaUXXk7OeSNamXR7nrg52Su/KTt/eSPCFzeoio7iY3vORVHeaHpWs3y+ipYf26jobCXk1cLVjF9BgaKQ8UIEk4JobP8DZM0dSC9SqfPLDnh2e6k9t39q8JNd3MaV90E75j7KuZKZZJemgTfwdUTe5c8Bn5uNxCf3TK5iuMxVxJXD1PTU+9tadOMcx1qXGJ3cb3nuH7g/03z2UrmsQfIRf/cZLGBqAdGIWhQpJph2OlUELy5WTq8t4R//c0t+IUVTKieR2A1E1U7uGurYXL5ymVtiLnckbHeLMEoxbJYmh7d4xn4mWF5hcIhAZoHvjqh+shIGNwCfXJQGswpnJNML0vWzQNhsJ1YcTUnHC0P8Y6nj9VmXMpUYuJLWuIRuqBS5lkS7ChcQMXO4wfad4N4RMHX9jLYytT/wOoty1KlEalUzriEMahdDn7h2DsLzOJL35SLwpVZ4NVnInvcE89IzYO4wyJIz4NdOfBYseoIv20Qv7qO8B7xhRtTudUyynfaz1jmkT8F9UgZFcdBJqg08MH6VdQSdrlKqUGSGsFAxtB9OC7yv25xznJq5n5SUwpLmFNbQ1evjOqqsogzLg8vClnH52aVuE6TfQWggj1wDjxG7jUj/W7mHSOsDI6AhtMWrP+2OVg2Wx9Bab3iLivdVe+mg93LH2FvF3a8iAdcDRseeNZj2UeJJfYnmzpsRpm+CeJo8Te1ab8UeOeGebDsnVTTILuEg+qe85nTuG8+PmgOs+n4r+781gUSlyoOO2Cde7QwES0X+oENbplkkSZM719jK09dcnbG27vqoeh8rTrzO9ygM48IjQzZWUJCnAIP4Y7VVrcTBiyrZhRLikSrVvSCvWU3K7KW18pnOJh1narIx0e6w+bctledpWsEGZJ9fwk/ae5P5ZvACxfM/2LOdDFqshVbr6grRIeSNNf+tl5nDunlOTUEY8fGNt4lsr35UgKwPwO9TxACZGCsd25DuEtHum9DU/GYli2+rgNaOokcc0Xtw/R8OuN2pa7ohiD6ACjJ82m0kKC0mBBymsNAdo3bDXv3yoyI=","layer_level":1},{"id":"aad61788-1dc9-4682-b743-47188d7aecb6","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用检测算法","description":"citation-detection-algorithm","prompt":"创建引用检测算法的详细文档。详细解释引用检测引擎的核心算法实现,包括BrandMatcher品牌匹配策略和CompetitorDetector竞争品牌识别机制。文档化置信度评分系统的计算方法,包括关键词匹配权重、上下文相关性评估和结果排序规则。说明引用上下文提取技术,包括文本片段截取、语义分析和相关性判断。解释算法优化策略,包括性能提升技术和准确性改进方法。提供算法调优指南和实际应用场景示例。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":3,"progress_status":"completed","dependent_files":"backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:57:14.593043+08:00","gmt_modified":"2026-04-22T19:21:33.125768+08:00","raw_data":"WikiEncrypted:qByx+WzXalKNnda2aYUs+KheFrHbXoPYZO+RPCaekyWxjKaQvamRZeOm1WgroVS/6iDS9zNWvth+zIYrS27hz/NZLNtt2wOUw9iZG139S+OGMVcZB6KjsnlgG3fSA05ZEdrwDfB531npeEpy2DodlOkcXOSBrgCwkOsVexBDKcWLpthBpfOCieqWsVnTfFkeXE8VvMLROtjojlr+6So18lnYzdEekhgU4Az61W3QEoXC7l+uPBNpRUYZY9z5nLzihT1o3I2bDEfAACTaa8pU8izFltiEd4qID4z3TepI7IuVr7oTmPOaD4MzHULu/4RaMo7/7c9Ql0uGsFrxRb3QFXiiH6QZN++2X9EDTl4UjA5k2E+OTcO2UOZm2dV7vi51lNAZwI50VwaIjtaC4LrPpX7fklk3hQ1qbw4w0FPjYlraJyO5MLseOOQXmURr5BCOhJcWoJmwJadtfh8EAO/9XRK9CRjr2wpAuL9kan2Vkympa3UCszQwVox0j4IkjJNYlG/7UEt2ixgTU4pQi+CAJy+8tZGJxY1gk1MCILniaClaQQImJhi6TfYfWSVywTFVltVcxPd7kMwK116KQmtoiqet/DRC4rzqeEbb6w8I7HZu+VwSR1TXSN8teXJTRMAFEgg9vh+vAOconlX3LzcgvFPohvC+teXJqTADp9XvqcC6Xh41G53xVAvDteT9pJCZHMZsfgh0bErBFzrvnwSObsmJEkvWnlDRN5tdVsRIk9LGcvaflUwWHmIof5SJj7wO9fSm2BN0gW+VA9nbQxyuHt8YqvNR5D0WUpbY1/UDw6IDhAxuTh/6yyVt0HqirNDXslgDardkMaphsQs4xh1fShhK/PcG4y+xX5VsoXIm/tjfGAEXYIeGOHtVuldTaCxG32uSnuT/aFQh7H6df2Hhb7c576oZ6QbZ4HyiG+Qa9iZr6deKWdGhtuuUzj3FBAXLtLont+yuXSCWi/AWM5MOMVyScyci2LKIjH5haWCCgS4nm9tLvifzUgmdeycw/Dhve3nrgdkgO+bIRuUQxXRIxZRUdxEr0DKIa2tEKVeorc5pIX9m1bErC53nDhnrLBj4/ZQjHp33XcgGQ+4jAfmWK/AN+P/SNbyF/K6O0qlKXPqQk/w5bOZWCtcIjrDLhyxZce/pYHOGotrSGaKOK56cJA==","layer_level":1},{"id":"ac0658da-7670-4e41-9e57-02d9d0d50680","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"报告导出接口","description":"reports-api","prompt":"创建报告导出系统的详细API文档。记录CSV格式数据导出的完整流程和参数配置。说明报告生成的触发机制、数据筛选条件和输出格式选项。文档化批量导出、定时导出和手动导出的不同模式。包含导出进度监控、错误处理和文件下载功能。提供报告模板定制、数据格式转换和性能优化的使用指南。","parent_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","order":3,"progress_status":"completed","dependent_files":"backend/app/api/reports.py","gmt_create":"2026-04-22T18:57:37.837258+08:00","gmt_modified":"2026-04-22T19:21:24.246329+08:00","raw_data":"WikiEncrypted:ncgUburcUGIQoFYRn+jCfmA+PbmqRFCE8+U3jYVfh2v8RywptgptFxq5lhwZlmleN1AF4e6ox3Zeepx7xqM72ox5n+mZFIvpPAV03iG0mffmuvwBURuWuzG3zvukYRbxLcpPqC6v5q4GXBz/rMTsxy+K9HHfwtlYbga6fioIcJrpFn0O0GBCxvse/EcV3UFGM+LHRaRVZqk3N16dHYVOsIgwcqfz+E1qQhOc9tSvlN8OuLBl1z0ukshjGXiX/lY4xzl1WSrFXAIsz6WAKGLPlkePgVZg61CHsK9/iXfq1HIs4Mv/RYwTtuMKkyWX9+6LO+AwRjoeHSIVgJsaSwMBS+MqugD6JwGdLsb5/QGcsDSVaN1zVhbjD1WnJ01uK+tBWcULWdYGAkgo7z9A/YQJsV8PUfXfdZnfuydZi59mopfaX1AYtCXeceMgKnzkAIwjWUl72+Pwtvdke5upjMFgEvoy5NrCoYwpZJBePLoPrgu0kURoy/vWGZ77WhOuGQs2/cn/pk4vCFes3r34gglCIF0tHwwh9piyAabHid5VZ3EIuOlhBHL4O9L6zlAgO0opbo23bXt7kIR8MIjEqb8b3SoUIGY7PElOLeOIwJiz1LzOnccT84S/avMIJR7fgzi/me7mJyD+8h7mZ3GY/AsbFhi2oh6bcqc7U1UcO40wTqx7myMlwrMOo9zRr+aAfR/lqH6YwFw89kkxflBfKQ8X7UwPI/vFeOnYkPFjj7XzgHUtclkOUbxztMSSnhxiBMGzbNf6/hnfqT9O5xO2ZF4ufJ0t2Ci/vTK7mqMRvj6sBAzXnGCig4zpnDKbOrVJnB53v6AnqjeFLvqUCGI5Aj9nn+g4LDMtPzzDhfm/HtoxVJjclFmC6FQSLvHlh2FILylIvVxzY7rDDuK3bTiuZFz9Hw==","layer_level":1},{"id":"7cb1d921-44ed-4e22-8bf9-baba7ff8b7c7","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"新功能开发","description":"feature-development","prompt":"创建GEO项目新功能开发指导文档。详细说明功能模块设计原则,包括模块划分、接口定义和依赖管理。文档化API开发流程,包括路由设计、请求响应处理和错误处理。说明前端页面开发规范,包括页面组织、组件设计和状态管理。提供数据库模型设计指导,包括表结构设计、关系映射和索引策略。包含测试驱动开发(TDD)的最佳实践和单元测试编写指南。","parent_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","order":3,"progress_status":"completed","dependent_files":"backend/app/api/__init__.py,backend/app/models/__init__.py,frontend/app/(dashboard)/layout.tsx,tests/conftest.py","gmt_create":"2026-04-22T18:57:39.375268+08:00","gmt_modified":"2026-04-22T19:21:46.916012+08:00","raw_data":"WikiEncrypted:5RlNBsIi2/3o8ATlHuzaYHdvL7yJfTe6YPwFoSkO/GgZuVYfBQkVBn+1kZzpIDRMGSVFSuoDX3pyax2f9XzBxnZshkSCM7o1L+HEG+sgCns6EUSGCL3KfZi4emTF8vVzG/3m0dhVOWuoQXf3TK1+2Aa07EE3HJ86aWB+sLQgQyR8gNqS+MsRztbE2Am9O9oDis36vAh+tGO64VIsi4ulSBpI8D3+dRXcAI8RsujwrZpp57UaW+DyGg8Jkp+WqqjfbgBGcdkno2KfRFyWKqKLB1g6yKJCePYymOK9DHhXbdBC9mKr7EWc8T394B1klPsqywIZs0i3xy/Pr5FAuzklEn/8jhNkYpmgcVvXaZ43AUVTklSOgSC0cwvfeHd91QuNSlfIbIs9Xh0pfhmz3XAts9WErkdoph3YSvrNDMuXK9CMNhlu9XMkMCQcV7ac8ax69JKW4uVaVHcjbU7PbzOeQ7vSALRtfK0zhIWlbQ3za72G9FvDogDqrLfOBzEXA/cyXMdpeZP/ICE7OsSCRM/i/yU/K2YUAWnRJczSn3cX/8lGIDywmB0jU+IL4l7eteQD1Ea3elS3ne3N6t0WqX/T4jybDWQQZqz0+gOrFuJUKTQ18p+2afWRjcYZnqg0EMvXxpXaT5fmpQAxMA89c70flWUr6l+ZNckhODBS1Uj27vp+ECTFfhbNt2CmqrDWIfdobRz1gXYkZI6LR+xgc598+CJDjc6zizQcychGbsbPqawU+CCQfSVqPCknZLlSyJrMF+FMoe4jm8fpOVyOOfqGN3N04W6++aIiU3eZIMB0F/1pjONP/d5egIYaJhs0Zo+ciWBBR+Me05kVd2tyIK0ldRH8iELZu4XmfrNdcGPMTZsENU4lZZiJxIXbeoKUQF7KbjsDcLTmuXfl4jcPFk48k+LwUEE2fyaAoG6SFrEaDZiZ/yR292cbQegdgcOrF+/QZDnMqVS6yFRaljF5C5+ce7VNxUOs5dzK46Z/0xD4kXHkT4QT5/727yUeQ8KmshnsLpu0XgxdbjIAKa0UpiByR2sen9DI8GblyzqpH/4jM/yMtc2COW+MLDnPw7xho10kjKNljBjsabSa5q/wLnYGofR/pA1CmnrwERR7Cytik91YmtyTb1D+rjh+uOjSVOB5NqjX7dqhFcV0CLE3KfUAkA==","layer_level":1},{"id":"c45e66b9-1ca0-41da-a796-6b98f394faa1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"运维最佳实践","description":"maintenance-operations","prompt":"创建GEO项目运维最佳实践指南。详细说明日常运维任务,包括定期备份策略、数据库维护和系统更新流程。文档化安全运维实践,包括漏洞扫描、安全补丁管理和访问审计。提供故障恢复流程,包括灾难恢复计划、数据恢复和系统回滚策略。说明容量规划和扩容策略,包括水平扩展和垂直扩展的决策因素。包含运维自动化脚本和CI/CD流水线配置。提供运维团队的职责分工和应急响应流程。包含成本优化建议和资源利用率监控方法。","parent_id":"803bfef4-3985-477e-a61c-915a246d0061","order":3,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:57:40.355828+08:00","gmt_modified":"2026-04-22T19:22:39.446821+08:00","raw_data":"WikiEncrypted:AymRokkaRBrPd1uk5umiX/dhQHTPPm6nf5mmDPb1IMODwfEt6djM0VBnDWaMwjVsVSuT1AHD1pfVap7WBute6Wsiarqj6ltamY09KvCs0YHxEqOor+0AYSzm2Aa31Dwx0HGTr+fgwTnE6RMJGGceRIs4cV8RBM7Bs4/C9pv4JQQe1wx9fBauJxXtVZgZmkTwsQz1zMKUv/my9/bZ9Q05aHGQVWSs0vQA7fX+eO9Ugt8ztv2KzLkMHjTPQwDUKBMhAsMb47fa/gUJRb4vX0XaRC/0NRwbOvV9kGE8ZhfJSMzck20DTmUNjRs+txGlORGu4UWZsefqLmppB1YdHehQUnSp53vMgJwj0a9BHe2ZU8oB3BBo+Ky3c3OR4uaa4rfHtatz+jzKcC5vq+Oa2OkwFMyKF/rHCf5c9kOD3c9bg/wQwxJpIov1DkWxrbmp2EHHUtHsb07ASQhGLV3SX7POirp4b3urFGRk2MwXKxT5U/gA8wytKMJhKBFtElvFBq2i7nSPeaH2xj0DS3o9rwbrhRJQvLfp/3z63umdp/84RCiI8SwdYgPx4ACqLY3QKXNo0LIi6rsgWkaf5Suyks+dimQcPtAllHZGQA/gcWYidV5oQCnhHJ/meCiKRy7Xb4GttMbIeOA7UNNRQ9IFS7wyprb/n36lYgLOcuQ5Nugly0pl7iFTkl4qWn4pZ+zE4TR9CK3+3oihqJMUeVFdsWHHzgVsh4Vy/4MCPUipHMfRj4T7BabCmkvaTRaf6oRiYEXPGH1mUXCLnQuty4lKx7e8LxdqWP6gciPJOcuRMBYoeBHqUKw/JNmAzN8FuypXsdUryS7GDozcilxOcRE9j3D0JEW+8ONdKF5sp2JAXYX0mhqtfB+RscbqU7E352fF8vZAqHdS0XHCguOUcPuOk1PjzrKK0PJcxoWJPrW1H76CpfhWX9kC1CX6ji8+oMevPaHlwwFIAPnELyRyWOvaAia+6TeiAn8YTup3BXf//p7UweBdBGz//qMDvWoMqMf67cKrFP45gozQjSEYzm8AQ8g0Rqx6ctmJotfnBMpbUoG/k/Br9U3yCwUW5C4ELNIkZ8HMTq1vu6GKzheTjgM5lsZSBhR9qgPwf7cYyU47KLN2oWaoSG9Ke9U5fc+blB461oN7Tb9p1M9jYYAi3IfY13WbWR9kQ09yQOl6zNP4E/TOZ/WG1O8YhDVo6O9b5nQ7Txck2F7a8+Oqzy404YpIRpdXWJvx2sNjxCQXQVXqKKTnxP5lOsLb4vYZqXeHpIw8VawHDzn9M5zowBo/3M96UZSy84F3QEP3JU1nF98Rqg82vqB50gv8dY6wl5RPTzKd+Fi2","layer_level":1},{"id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据库设计","description":"database-design","prompt":"创建GEO项目的数据库设计文档。详细描述基于PostgreSQL的关系型数据库架构,包括表结构设计、实体关系映射和索引策略。文档化SQLAlchemy ORM模型的实现,包括模型定义、关系配置和查询优化。说明数据库迁移管理、版本控制和部署策略。解释数据完整性约束、事务处理和并发控制机制。包含性能优化方案、查询分析和缓存策略。提供数据备份、恢复和维护的最佳实践。","order":4,"progress_status":"completed","dependent_files":"backend/alembic/versions/c3d5e7f9ab12_add_user_management_fields.py,backend/app/models/user.py,backend/alembic/versions/b2c4d6e8fa10_add_confidence_match_type_to_citation_records.py,backend/app/models/citation_record.py,backend/app/models/,backend/alembic/,backend/alembic.ini,backend/app/database.py","gmt_create":"2026-04-22T18:56:47.082886+08:00","gmt_modified":"2026-05-23T15:19:23.714682+08:00","raw_data":"WikiEncrypted:Zb5TNaG1u/mRrgPr+sDyCqW7t7yX8M+Ha+5tSgGfMUOChQVv8Rc8RrXA+lpSqmcv/gkaDzP81agTYjHvX46erg7PWFncGZ1TOXKqQP7QcGfliH5ak9tnEamgIuPyt7GD7X/ktYWZNBw0rkib1u8riLrYblHZPip1fA5nWgiNve9JAWR8A5LSXb1/MkK85pGhIT0hbxgGSC6PkPVIRisy/D8xDYn6rcwMs8isn1Q0j0kMKiUwDu5D73M4vDsI4y/ZxAWd6WYEFgkqYOoeV5KveiHRDQ1BWHqQDFCNR/UWM2lxXlj/whmN8VaSk9Ye/JHiiNYbkSuvcUcO2YiOPia8H44APQcfRpcKUh9SBToYsFV8Fu3Sz330VdqGSjrk4hlw+DAQy0ANf9SxneL1SSgh7UEQb3mCmwf4ol0W2OOEKOPj3+srwFiYVbOmSKLMUezu4sRx8BecH0DQJj+w6u0jFTCVwHJcsSZXsJ6ftM8zeW4Gb62L/9E3eGd5gznXE4MrfDGV0U+SHOXTHVLHjIiiDCFL5EKuriwMozfYOYiXp1kgte0NR3DLzOoxAk9NQViv6c9ckVvlxSytmvKn7bbuCU9m9ZkZwa/+maXmuIEHvYRmeD0JBzVAPZtqvr9Q0yjLJDSWQ4z/0GDbEER7obUFIM+E+N8/yfexWunfYvUfL0mWXCcTd9J82nMzWM+Wgy2xUD086AHFPLXHH07CREuqOjUxZsvdQDG1grk7lObH8izbD8w2Zxaayy9lIwqJBEPCqaRdF14OuD+avHkK3Llo+7V1HYjHFYLa73gJvxSO79Ww/qvzvLWynNytnZEci9NCrzeZdZ+0TKrk+9i9L/5cU33O7IFTcVDDUQKU/ZCbP4D+ICH+K0AmOTiZaS343BGpR6hGlcrljtEjmFjbtENwJ6Dj67zXXVvUFWRlWwnk1ueUMxE7uNPzkF8R6XnOJQZxjv1ZhoYTrCdpi1eofq2LSlp9DGEyVNgS2UvYp3ZKdt2nOQi+NGHfy4nEMXUm2HiIciMAWERbdIZFH7igmgNwCQvvOKfnwxsB9aToLxzFTklkYilSbsBc+lBi3dbwXpvyfvcETruYMAK6xpcl1vfnkx0UVzmWg5ScYPlMwAyAkThsdYB31r9HWM0W2zlrsan196zyJUp/Ga7/dTuGbTW9g8RIVFlbvyO2+q1QBoBXM4lBDOEZPZPxpCubiCkbvshTREXUBElpgabfbBe5oufQCqpMvpO22rjfEwEMp4XMcih8I7Me+WEJuO55dx7hs54WCDmTwEa9xLmb0hXAKG1v6asdjp08CZo4Jbvnp/BrARqvkJ04j9cZpY5ybL5tKEtCbWWnIkSTC14or1XZksHDT3UZgFTpCOoAIbC8wOL00HXgI+rkt7UFfccjoV/i+y2xOlkwPUt3/LqSnsYRftUSpnJIj/vsMl8Gt25CJqSzSyvVGY59wIhWaWWzMldJK0IvOnc8JOGNTLwumjK5BG1apFMsHQ5IsoaZlJ8jed5aM7jLsu4v7wCNEpb1mh2FX9ntfdmHo4fqvttaKBlZqzO6/2JSNVRJz7KekqHYM0Z5QJ4="},{"id":"05214c1a-d804-4f3c-9048-20ba4de3be0f","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"引用检测引擎","description":"citation-engine","prompt":"为GEO引用检测引擎创建详细的技术文档。深入解释引用检测算法的实现原理,包括文本预处理、品牌识别和上下文分析。详细说明BrandMatcher类的设计和实现,包括品牌匹配策略、正则表达式规则和模糊匹配算法。文档化CompetitorDetector的竞争品牌识别机制,包括竞争关系定义、相似度计算和过滤规则。解释置信度评分系统,包括评分算法、阈值设置和结果排序。说明异步处理机制和并发控制策略。包含错误处理、日志记录和性能监控。提供算法优化建议和自定义扩展指南。详细描述与AI平台的集成接口和数据流转过程。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":4,"progress_status":"completed","dependent_files":"backend/app/workers/citation_engine.py,backend/app/services/citation.py","gmt_create":"2026-04-22T18:57:02.318113+08:00","gmt_modified":"2026-04-23T20:33:37.372717+08:00","raw_data":"WikiEncrypted:5AsZyvafBXiUtsQ5ntd2xSs3ILjH2jK3KRqQeqYdLK3xV++pdLq+4satUA35s4AktJpvtIlBIE91BpoSSxdMIJzlzjcEII8kW/R0EytB/VdNUbQKg1RverfqOp1bPEWLBmM0oXoe7+3qkzPC2Mf1ooT1qY+Wnye4CAfG78TD/q0AMQdykzQydTep7eypfUng3BGXStCcjUkwnitXy9jgftpC0/tEyMhSJIRwfEyHMC8pCZ3uBu05K/kbWJMAVzeN+RbpjqQl/AMRIDLTMg6TBQrvrH5uB7kEmNLnso0k4IwbKjYBfsoAT1f/RhrPR6uEpuyMZCI7868kZ98SRi4JNdev+YK7Ek74Y4AW+/z0d/9fpp2VQ3lDuYYADB2ihvzHrK09yCDPV5DfYbOE+YmgfP/W+1ZayVWcVf5jjw/kQ0+wXXpByj9Bf0MvKeJO8OmWNbW11YKf1Zhr9O9ssfAGhQ61tEWdGwr2vpPRZecLhmP/3vAso3UexUhMF+42ursRQIxusBVhGnBG3395aphiScvidcQ3AWZDt7qWaigup/9WWvvwKEk+gWaJBnO8dib6i/mBuB+XC33fXmvrkk6ESP9afV1Ag2XJnNosrx5wpwCnwwVeYm1+mo2FyjpkCyIesooi9FNVuMYQUiR7o2ORBBXyp8r8l4pab4wvhmQ5F/kvyrDq2IUoSgVwCe1WVokpscxHDzemlRiqQALcb9vHFogShoOIw4NQd8JE6Ciw2NTcEbgq5i0hiaO1w/VhbUyxoqA105/8aSzbEwdAcuMG9ciHKwbMkoyR0UaMKUZLJy6VO02JFFpRtlh3OD72t3VNoDS4lWyWJe4G6NccX+XAohN1rsZU+ROCL8Y63mODms+oacpzuNvCQC0f91XvoRbftpDjven11QkJUdRxC+QBid+X3RB5HjEUZI6amQjQESEX2z28T4td0i5MNlp7IQfJjM00IuaVZmFavGuu+RJfvR7n78hqrcdjNGJE2t3TTozXstxH3HLmjwKzaA1DGdcvjISEAlWpSDq1Z+8ExFSDbevtUFgnb30/rRPe8E/+VsDMR1FqWh+HovxPuOeMpbUi9ijTGv8ynn1DWdoSvT0kIfsNMhReSibvIGRprPdW7oZEiI5y1SQYXU4kMBOpPdNuCyaPRA/3Mx5z0o+l66QqRA2tAMfS5JvFR53tL+M8eEjH5xvgW0VmBTv2+9VGk9aRLHXSHANLk78McmWR3P66okFWF0OhqkaLPqj1lqn8SMDBv297qL/7vaz/5ZMq+1nKCtq/I4rY9/FziNmhBZi9jtXj+845Jyt4Qi7hprnHQYqmX7caLgy44MGdtGDcZ/fxMNY3A2QbuIeQRT767L2gpffBKmqQxLcfEBwxKol5OB8/jdyvVTpGLMdROGD3baQASEk3njuah/PfjZcfuARA6oVvcpj+RhM9HEGKondRlyBHvD2f5p7nK7WyubfWPvcD/iKl45JOn7zLMHQYvIYu5w==","layer_level":1},{"id":"bfca5ffe-8905-4ac2-a0a3-8e4dc43533b1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"数据可视化","description":"data-visualization","prompt":"创建数据可视化的详细实现文档。说明基于Recharts的图表组件设计和数据绑定机制。文档化趋势图表和平台对比图表的实现原理、数据格式和配置选项。解释图表的交互功能、动画效果和响应式适配。说明数据预处理、格式转换和实时更新机制。包含图表的主题定制、样式配置和可访问性支持。提供图表组件的使用示例、性能优化和调试方法。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":4,"progress_status":"completed","dependent_files":"frontend/components/charts/trend-chart.tsx,frontend/components/charts/platform-chart.tsx","gmt_create":"2026-04-22T18:57:04.217105+08:00","gmt_modified":"2026-04-22T19:23:03.405364+08:00","raw_data":"WikiEncrypted:LlssVZ/E1BSUywfa50FLlWyGoIcJJpOig8KP9B9gWWZZI8ePi8CsG3BxaOR4OzxCxm2XiNUDCA5f2LMwvnigr2SlxVBiSNHUI0lCgSHHEunmkPytqBjFiqGB9yeyKz3O1rSdq/m6COB07RDEp6Tymfd/Ich7hNqr0ALiJKFBMfTRXbiXa3naRlzgzc5/DA1h/zbAk9yl3yaR4bB4p7xAmyNn8C67e2gxrbHOKN7NK15dfXoIag0XHJMVwFE6SysJ+lA7fykhvt72SHx+Qz58/QamURb9OcCEnEtIYqW1uga1vc2HXP+r8Ud+tutKATUxPch908D2Dm70HjZTkDqV0y1RwdTE86O++EPgx5Sx24CmB2Y9KEs2TsxQBSxas2iX7ajhgIL9xFqjJIMVJWfRNeL/ql2x/OsrzEXUWybjh//bQHE/MIs2lMcn3jl6uggDT3q//Zf/jugKwK1117XAp1NDps6xhJqmTf0/J+uk2DjJwURNZ+f/hL4XNyCoPSOpjPZMIk+ikrqwiBBFy1t5dz/fksmYdzw5H1wSGwFPks461EvwT7SUd3qHg+HDEWwCrMRQLhaalcb+5T4rD4Gg7Aa0Y5Q7v043Oz/0rnmFckpB7QJrcI4yUtnbNxu/HuY+NFZLqpJUrNC6MhZKZ1Nf8HjXwbb7FvRLPTJk/0J2UGgZIuFkHqA398GnAHSj3OegnBaKM+qHr8cVs0wfQ/uFwwYzgoBd9gSGURpkSSDhsDUj2XJMeQPghyYg+au4UrCpUVHdYOyliR8OyttchGTRgDox14AD6X6BPxBueyw2Yb6orKjSBwNfDa9SZQK8dW9S0BehKqK7QLDHIzpglx66chB/QwWwaryM7BrEciDg6cdFeFQSmV+EgDmEePwse6hlzNdSXObTbNXLDwYhtifAxjK0xxhVUCtc7HVAFKLROk36HCFnlzxLpVmtppYzoprXfyXDe6BHU55d+PSdjtYyR7k/tigqJv5jX3TTrH6McF+/v+eR2ZtsTDIjWz+prq1cMVTVPgIB9WoT0+dXP1fMoZ52xLzWjSkgrQ7djAo7jyy1G9plvOx0bdGh5lBGOz+/zY7MTLVaKx8eK6kKS+juFkRK2kCuesUi79TGLidetA+vkruZiHzNPBJWntDodb79","layer_level":1},{"id":"b32b024e-2d06-45c8-94c2-a07fd25ab9b3","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"快速开始","description":"quick-start","prompt":"为GEO项目创建快速开始指南。提供完整的环境搭建步骤,包括Python 3.9+、Node.js、Docker等前置条件的安装和配置。详细说明项目克隆、依赖安装、数据库初始化、环境变量配置等关键步骤。提供docker-compose一键启动的完整流程,包括容器编排、服务启动顺序、端口映射等。说明首次运行后的基本操作,如用户注册、创建查询任务、查看结果等。提供常见问题的解决方案和故障排除提示。确保新用户能够在最短时间内成功运行项目并体验核心功能。包含具体的命令行示例和预期输出结果。","parent_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","order":4,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/requirements.txt,frontend/package.json,.env.example","gmt_create":"2026-04-22T18:57:13.330281+08:00","gmt_modified":"2026-04-22T19:23:49.7972+08:00","raw_data":"WikiEncrypted:1aHEw3M2aeluf1++NE1n1HTCzLNrSYNKzc2IVp06RQtbuAYcMEXChpU7tJYS1f3O0opR6Xc/vB+l5keQe8PgCR2ncFv/1Td0hCZ2YAOzrKcU9vT19aDXTs2wVsNg8N0rDLvVcTazfsrfReCkGbF3t4KIDlALR7E9k/sBc8Aux87FRnIqhElZnBvZS4Wsv6VYjg+rG70cB28ZbZapx09FwTbE2gyXj7Ck6qNOm9h31VGeQcyIEPfTlQzKWWghd2UuAwraAXbHFeTBwAzBOPZrVi2iMW5N0fiPvrofJe2RpvtWwEWsHguXuXUfXywdpjyOFbnrTokbwQiiwiHpgbktPSypaW3QvBywnGVAjxPBIfRlzbrxj8jlb7w8YznQPbWcNRuYRt3TVMBHR1Ix8UjdR2JwWu4yZQUrLOP4XJ1OVoFdLu5sT3ug3YetVAWSBGUiyUEIQ1U7QoHxxE03qI1ZmrGvC069cAhyU3YQYL0g+PfXWWo86/F20gUXppepBbqg0yRPlCX5asdDuL0vX+i9vl/JI2++deWQKu7cSc8+5tRNcN2AF8Klslhvy5KUEZpxqPaEhxXek/RE8thYcMjT02y2lWMR/WID/CEUm0DZjOC2fQE7kYjogUTC8OhNTBXocpLyn1sbyngxfQ3KsE6+Ysl41LroJ5F7SN8+p5pueRZgBbM32odMU1Dil6T14I/HwltMjiGAjHurPSB8hcX7nNvkuZnVTE2YMjB8ZEhhf76D9Pp1naI3P2d3j0DprvLXRiuPSfO9NBTu6LwZKuMaI2MBEDI2zoV182wdrC1T6AxOiHNcJXYiaF+ZOpMA0vabvcycoioAE6VOZ0mBQ9ZPVSZDf/Dw+VTsC8U1qruh1IAQVYCHsnjY9etX9sTaj6Izd3VrvgQkqP5vAteSDZTy1FOTlTi3X6RzcurXdR3833HqpXa/a0ot8JiRdmjIG0ydOuPYeZPs+Jb0FMN85H71mBziu41udCrikCTPBRTVz6VCG9yBdOgeW4s/iNhPqWCnDibKpfJy1GfSyZ7Jja1d4K91Y+IHVrJxB0+TZPezxY/htgMg4W7MtRoOOPc0eRqst/S2zmEgxMMpU4dfaQIne5zGbUEPNb24qp3HsO9v2un6P17rFQV86RwmPCnyngxtddo0vUNesY0s594GhsGEquA9XlaYa4/KNM14pVDEm4ReIC1JvvqdiQdUAPv3nMXASqe3FxbJmsi93mpWhKWx2q4W+P3ZivXtxhQ5OB4Rs2uXmArlB3MNPKk8TL7wHCUAsFUcCGoPtT2+ov9ntDTLyjKsb0YUGjYUqAceHGdvLCM=","layer_level":1},{"id":"15d6170d-716c-4d2a-833d-81211a59027c","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"平台适配器扩展指南","description":"platform-adapter-extension","prompt":"创建平台适配器扩展指南的详细文档。提供新AI平台接入的完整流程和步骤说明,包括继承BasePlatformAdapter基类、实现必需方法和配置平台参数。详细说明不同类型平台的适配策略,包括基于浏览器的平台和基于API的平台的不同实现方式。提供代码模板和最佳实践示例,包括错误处理、资源管理和性能优化。解释平台适配器的测试方法和验证标准。包含常见问题排查和解决方案指南。","parent_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","order":4,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:14.593273+08:00","gmt_modified":"2026-04-22T19:25:18.719953+08:00","raw_data":"WikiEncrypted:Djug3Ni1DAZ8Du2qShzHYuqLmnJOyyKhsCPSfayzAMoLf9J+rFBy0LePWIX3b5/HwiLgJX57X2JBlObsW70y9DLEgX5HDr3AAeBC0dRNACFssPk0GwpdFdJeFwRtoB01ZTdr+IpYAK2YG8gaEA/2ysFJOZzxpGWgTq/Xz+KO29a2kcDgYhZKt55uqT/Mo/5Dzr6AN+qXdLL5xSqrvCkpmhYMFmzgIBOUjJM1mUISEtf/X+gK0L0wXSj/tCJnDQtGJqbFK24HEYyVnkon1GdnIvb+Vptmby7Qg9iNT/xb8JEVTTLM92335BfpTwTp+D4fNkMNyZgXv/XW6K5J/dLRulOCKwxJxPROAyvyEc5xLI8vh6BGP2+b8TgKAKILZTXg3SemKVhGrB3MqY5+V6whOOMT57LHnuwJUEMNMJsswFiLp6UbAlqwiICRF/Jnb+bvCliw4xXvKC6xfAJDQ5qAtcTCAm0uGslNVB5T07pzLFy5EaJS00hqRmvac/P3e8UyL84KjzdngtT3yZ95yCL30Ad9SpGXt76JgCgVJoPFcnPYlJZiXneeB39wFX7rogSSye9XkcBSqEt2ZITemhNHF6LmqSUdnA3rX85S/zDmRiN2NjS1Zjvgc63JjB4B8gQhw3rDllzHDLPBIO3PNInvmVsx5zHOjAMZmyIaoVRtB9BQQnUdHn1WvHdRXmZfs3eVA7jNhDQmTtBzdGtJ31XIHAVkP5ul/NXNBKUytIXDS5hE2s/ZR6j60eIWBlCNxNIlj+42vefIOU+e5kJufMVcBv4aXyQHpunohRHMUYteEC24NO2CW1FNZJlH9BEyf8RKg1/0hDEmySMxcj/S/pXTp5i8nevE+JleHdj3zeyWlGqJsJa7arZV/Kj7qPJYtN4VHoDGp7MFHgKvq6W26lje9EuwJEikt3hqjinocemgMjzEx+PMVPovHIBXyCfuSOtygo59bhUm0pvPgdMmml9UgZeVV1GMzDT//kfmf33ZL+aXTl+zEmnw5fZYwccKfmY6Q++ZjfSQLB9eV6u79F0yq3zh7zGb4RqRR5ZeL2vQaNsL3wyqgNppyJMYSC6gX+ce1aAimwDx4Lr/EnY474W0FXvid1Xc6Bg6KdPrwnKJJpi18zMOmECI68RvMpwmM+92oe/m3dj6YGItooug3uasMy8SPsvLi1RV2F0CQD5CqYs=","layer_level":1},{"id":"7e66719b-4a8a-484d-889d-10fdc76788bb","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"AI平台集成","description":"ai-platform-integration","prompt":"创建AI平台集成的详细文档。解释适配器架构设计,包括BasePlatformAdapter抽象基类的实现和扩展机制。详细说明Kimi平台的浏览器自动化集成,包括Playwright配置、页面交互逻辑和错误重试机制。文档化文心平台的API集成实现,包括请求封装、响应解析和配置管理。说明引用检测引擎的工作原理,包括品牌匹配策略、竞争品牌识别和置信度评分机制。提供新AI平台接入的扩展指南和最佳实践。","order":5,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/tongyi.py,backend/app/workers/platforms/doubao.py,backend/app/workers/platforms/qingyan.py,backend/app/workers/platforms/tiangong.py,backend/app/workers/platforms/xinghuo.py,backend/app/workers/platforms/search_engine.py,backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:56:47.083138+08:00","gmt_modified":"2026-04-23T20:31:36.620063+08:00","raw_data":"WikiEncrypted:wpnkiTiqqfzSOLf9jfRAk0Q6rmj54V4PX4cfdCN1v7vUnV27EqfgO0UCzli2MtUnJ51CgpvG/pn/E3FsASRJX83W5OtoHXDNZ4j26fcGYWMK9zRC5hi8J/dMZoaQzJzzsT8qKvXJnD4D7Bjp4ZqFEme7Smze8hNvF5wytAi0n14HrcR90C0v1NYf6UWM/I1F5Nqo0+3N+pfMTr9vJAv1ZqDstNHpvNePzJyNYVmfwpIE7rezCdxATA1CVuPpwaFA5xsmJ+vkqC26R1ecrjj4kaKngH6RRRDgQhhQ6aRB3vt5nqJTkK/GUHcF5T1XjKaL+a/sKF+40wgULRooeO7uAuC8Zv55v4uHR206FqyBmzQ2n2oL7aEvTlkvDbpN4K4o46nOw6eAh4cC2u+M/6UyRJ/vHl8dGbnZjB21BICs+8mtyY9X8HX95c3q/eXaBcsnPvE/pQo/8Z6wSj7GzmxfueajIQAC0N3PypyM475sPJJAQYRRBk4tB8BeeHAheffcSAiLI86gW5xCar2+kHIHTkRg3pcdkaw1EkhKeqcQw6ew0Z83+q31K2+D+G5Dp7k0yg57Yy+wQYoQpi482aVJTCvTl4DM1GdhaLBYK1/O9ybs6CsHHuhAMGPJeOCtMI8ehbz37vhncd/r5KFUwVm+e8+iVqLPjIA7A6uUm8oef8IZswkzAIcBjZTd0HQmfhdO7p2GfuJKvyAMwWchCj+pryelFxsQ1XiY4QCO1g7ORVxu6x+4/k2PNCOhk6gEBxOjJQzXNM+PjMhiZHJslw5eSbtEAXm+1F5jyhyYY972p9cQQS3iRFts9dQK7qtI8+zm8/UMh2S3rh9y089hgBEUB71Gg5cUb7gaiI0gJYh5HrUXvqt3g6H5zQQs+913IJZ7giMElPAP2Qjbk7hKfAuLl+gm7pG21vEiGBgdafi0W/SeGMfEfargk5rycBiAux4yqzolMzt6ZY1G6bSEdxhBwAL7IPHlaguENQ7PIDWDT1mlEboyeR60e3xngdX3d6vQeuuV5+OWjDecOeZTiBxvDIPgHbMXc4UEzS0YKWD8ao1VsXgT+V+KP4QhvazHdx0dXUhAJlmfrXF13WzadCYVAAlfJ5iNGkT47I5Z7NwqDIF2jO1g5hfgR/LgTwdLyuzF0R79gBMRfYZusLAkvoVjfKdTxjMIrkuXKoXEbgtcZDj99mrJe5eVpoCtl/nL+FDv5U8e1VDikgYWnXY62y5ZnhnOcvlUDLD2mJVlDEbnDBkMkFc2WW6TRTZQAb1pLCRTbsDr+kQD5BLd0YLql1xTFN8IsAKgz3fkhafmSS0hAEBsKC2Ntov35ZpS0cXcMYb1oGIIGPVAMq4Uk43QUUSLac4pkX/xpRkDI/wPdmaebMbCDw83xHKBNY4h9STf5rFicv01m7HLBHfkB3BTFwYsKGhOqxnJPkYnD0ZSz+ia3lw0eV2RoqWx6ITdxEvkaka3zPxNSnqrnTBwjBwTbLz5tXrCmK8Fn5Dd5N9xlYM6+6iveOBt9he/WYkedO6pClHq3NK1RmLgTQWpL532vkJNeI9p8YUcv89XqnwXSi1YhPMe1PKgYTDGoZvsPk66RDWaeTNkfhF/vcZudTvgMmZzQVRfZ/clH6wRHfgZzl1X4HZ6WJ7PKSSwwUBw/jkvMZ2rixaio10OXuEfyOqYqV4EoQ/upbXArnmYKjEbhcULNFk="},{"id":"850fc702-3eb6-45b4-acd2-ae87fec1f4f1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"工作器系统","description":"worker-system","prompt":"为GEO工作器系统创建全面的架构文档。详细解释APScheduler任务调度器的配置和使用,包括调度策略、并发控制和错误恢复机制。文档化工作器抽象基类(BaseWorker)的设计,包括通用接口定义、生命周期管理和状态跟踪。说明平台适配器架构,包括BasePlatformAdapter抽象基类、接口规范和扩展机制。详细描述Kimi平台适配器的实现,包括Playwright浏览器自动化、页面交互逻辑和错误重试策略。解释文心平台适配器的设计,包括API调用封装、响应解析和配置管理。包含工作器注册、启动和停止流程。提供性能监控、资源管理和故障诊断指南。","parent_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","order":5,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,backend/app/workers/platforms/base.py,backend/app/workers/platforms/kimi.py,backend/app/workers/platforms/wenxin.py","gmt_create":"2026-04-22T18:57:02.318442+08:00","gmt_modified":"2026-04-22T19:24:30.529121+08:00","raw_data":"WikiEncrypted:NKkj/YX2GdbxYjFllBaf8+HUgx0ecKFsz1U3HC2t2IRMbOkBCmoy+IYbhzuQ50K4pCdPARIwK+MaHbv1MDUXpcbdnvRL12GKezTnD100oXzQKqQkhZdDDC4nIEcp6weWLVGVffqyB7aL/dnt1QlE63XyJfCwizBlecxl1GDUB4J0O7SsTFL5gI6enVYO6hOzx3JrWnEFzirRjA6Llz1iFiFUWxTjxjToT1qkxAdREq2omi39vXL1s84I0XOA1blljfNNIGbpkxXW5uohJBndl6l7Bh23wF8z1LfdAavsFmljavCWqoMvA61Dn4jpJT9oDmaKXZpVSuxfMF2Tu3WOJZwISUGfGBJfdbfxNalhuFff+bhZR8P717nLoM3Do7T26rsqW/pr0NJL6aKxrlPCeIzL0v6Ct+HU3ULHT0EZpG8HfU2NhGWAJd0NhX8RZ8B2ZpfXZKioKtCkLhl4oWV6P8/k5g1nWpnP3wpmDwvp+/pGBeaBcYSenwJWgcGR2s0KgVsEW1niM8+JLaK15wFrmKcxve0hIWBiiPnbZKscAYq+5hj3ecte8h/JevEf+SBNB7ify6uUGU3Eve1jXyPeBrc2FCU5ueeJSFD3wu5pHlkzm7PP8UAbQOfwmENf/Mc1YRNi1FJsujdQuJ67474CyCTkCWFhTC539/6iIa7hN8505GK99PxHcIrsPMMT5LU69r67SizSnWV5bawiMPKGosexCHZfhT1jrScQCKeuld0X/lE1WXXm6ADBbfxZrn/iEFK0zc0WKsnT0X/nQI+ycJaw40Cm+soCO6/KtdYYGEzpzViqi2KxYhRyey+o+yIi8V7nVsxUCbaVRVmYNjnK9yX+3ypdVpJLIJXQ5ywaUWfvqgCrsC7Xxba9P9D+0kmnq6jH6ZdIuubXp0yOtWxe+VC4bHAWoc08RoBdLrlTCGz/hmgi5S83hM8MN0gLdQtc2YDsc0Pxw60+ylnkdlKIefBmb7XPiD8RMRvcbDUCGnrpenbxf5eoWLjLWfyULNQHoYINDdIFvn+skLu10KkfTf8lpRNqd2uHkHVhTTCFh25GlRLAdL7QDHMMQbmwG9OTjjt1tMlW6aYJ/pvYQq95uzmLAiICIsf+nT4xgqoFK+tTBmOst7Z3+bj1YJCPtUNyIzC9a3YYfRwlB1ckjgJaCURcXpImdkDtdpl3GP2mtDp9O52ZDAQVAJFVA3wFFV1G+qjqGRl4cDFK7BlAs04O4fvskn26jrDYiVqgdF0pc6eIiPhAJg/1BabciIggV78rEnEg6jiNJ8AhUmKLo8JOvL/C3m1mfcaUbU2K7oK8damVm8BSmIypHMJfCXzHIt6i+CaJLNlZ+c+MJ4WhqgPWc263/SnxO24wH0vaRtqmZ8g72SSFVa+6E65bdhSUaIejIDvILaBv+73KdUt7LGKPmqKoftErfP4grQZACnS3zQLXmnMfdzurPkKbBI1PkyT/ase2Czwu5/LwHWdWDcRQD2uZmUjndsKpbR6/xVu5Ry5VLB/ds2BrgjUp5pD+Z0U995X4yVwpr9oCNxR5r1sl+2Wv3jotf19l+safw9XwODQoURKcJiGxtJDymJvVEyl3ZEe1Izwl7SF4UqtboIYt9vEoEIilsuPPDtujnpN5pkY=","layer_level":1},{"id":"fda0598d-7e92-4b8b-be52-92ae63c3cd98","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API客户端","description":"api-client","prompt":"创建API客户端的详细实现文档。说明RESTful API的封装设计、请求配置和响应处理机制。文档化API客户端的错误处理、重试机制和超时控制。解释请求拦截器、响应拦截器和中间件模式。说明API版本管理、URL构建和参数序列化。包含认证头自动添加、状态码处理和错误消息格式化。提供API调用的最佳实践、性能优化和调试技巧。","parent_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","order":5,"progress_status":"completed","dependent_files":"frontend/lib/api.ts","gmt_create":"2026-04-22T18:57:04.217601+08:00","gmt_modified":"2026-04-22T19:24:50.486294+08:00","raw_data":"WikiEncrypted:/umMwKXdJhL9PqhJYRia9MjBtE8cuBSpJq1+zwyrvadwhOTuxc7+NNlJizkRp6kCDsj6HmsrrrEG2WmrNf4m1kFf/yUci2Hny4otqjfpEsOXzmFIxnq13zAZFe1oDyDiHr+shS0DH1omM5IrOroFuNXfBlFlOGXuTKJ3wXXPweq+qAH9QLU237hwRdKdI1UNXoGFfFF9nN8NzOmkwSQ0cRMvswtunfw+yphm0doFqLjrjc0WUZSar4loGeSR6pOSLU8ebi/JkrnwesaWnoYc/1aUJBPdJqVPSJQzjx/Oupuf/R1ihtrn81TMYOUvEaKLk9wVSfSvjh8RGttelGQzTBNJsssgMeqcDh+Qz6r4RJeFKgaRlhn753ONhpYFsHOA/05biB01p6yVuJUR2A3I4tqTlKZ+Xt5K6nvklSqGfR/asdknv3YOkVZOtQxAjyjg/RmmtnslgrEae+k+pBRvgZU23ZT5nZ82LarvwQLYZlu2F16oJjpKEgT3cw98zGHlLEIanqAXIOhT8iR7Fwk6TTKreGcH+oOkFNmbXHWXAD9ixtGbLqoidjzBlLLSR1++hGoabWTFiJX2LKj3lCJ4z30snHEvEL5ruTnKMF+gXM+truHTDsrO5CuaWyGY3WYVTndJKFLi2PQu5FclItm6ykG7LLkMlOXcKTmOrUqOgQhgDR0R7UuPYneG3+8tP49Gar78dBGx+Da8xGwikj9K9OJYAlHpVo05oKo78qku6h+6J2fHgIvIyJPSC88Whc+HpqTBbVMAIjzOQDzTTafDZnEoLWczvFoR5x2aPLnYwXdjyljOhmpXH/bShHcfo1W4KEEzka0Yp+DMZpTiSyhBpA5iLdjZdU9RnTUPTwMtqSXfdbbf0fdgem+z3CsmiuZJVViFNkOfRqL5f7Np4ITC0v2XwLSWr/bC7gbUZiEQdwEr7jwVO1Bk6/MCzvN1G217W7/RUPA4Up/Iu6PRBPcC4dd2r16kpGY4U68Ud7F6iXnc1Twr1Znb+cuTdO4Fu2DQ","layer_level":1},{"id":"7416db23-312f-478d-8883-2fc3c41ac2e8","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"任务调度系统","description":"task-scheduling-system","prompt":"创建任务调度系统的详细文档。解释基于APScheduler的异步任务调度架构,包括调度器配置、任务队列管理和并发控制机制。详细说明查询任务的生命周期管理,包括任务创建、状态跟踪、执行监控和错误恢复。文档化异步任务处理流程,包括任务分发、执行优先级和资源管理。说明调度系统的性能优化策略、监控指标和故障处理机制。提供任务调度的配置选项、扩展方法和调试技巧。","order":6,"progress_status":"completed","dependent_files":"backend/app/workers/scheduler.py,tests/test_scheduler.py,backend/app/workers/citation_engine.py","gmt_create":"2026-04-22T18:56:47.083393+08:00","gmt_modified":"2026-04-23T15:20:09.061178+08:00","raw_data":"WikiEncrypted:VyywLMbCKto41PC5aDsBo+87rJy1wKhB+t/+dFn1cQKhRzLNGkc+cdUADwdeiVqAIwtiwaq+rwA2WFYQdbiGz8cyKHFmC9lmt3Jas1uZAz4Osy7WTe5xdzE2SEY35xhzdqPvBbNe/p8j0HjSJGFgENGbjEhhukipSO73yvj8CPLzAxa5OEqoQt3uMA0dCSgyFv2LovXFxAXl3U9omZ+jIerOmf0scDYFZ4Cjk4x8Bzb0xm/6wMRJahXUi7eKOQNBfFSlRnxNY+u8u6x0eLR9rZQJsBFNgTapyPe11i341lFAvV8GVMJsgmLfZeTV/A+CJWTGWbc7TTvNnWcbYK7l8zeSZ7dH4rEnOvERyY5kxDrOEwU/Yjdg0OIz0cgmb+dlRmAPiX3OWjxUXJg4aSEFFG16FvCKl2nOFUF8LecaPl1ENKZOzyeeouQpzJp6MwRbCvWKCbKjmM2LofkPlbYC3ljZcmitkM3M0iUQSDo8uwQ71JEBqciChTxdYCFkbs5lTGlaj7NMUVD0hinIuBaEJQ1j0Irfxqf1ncrLdx8ZNQfA0gzLgSYcvydd0BeII/j0Mao27RFzOAqYLYT4lwZn3J2ZefvqYbOF2Sifr+D0ZdG7elOtYhiRAUEHGhPSUWaoI5CpzqRPYnRva8JuLDZi4Kj0EyjpgPrSYN9dp01ryHcTMd7FaHIiskbn258Y9zpaK7mnlVvyKtjxlJL6MtuIV32lhcB+5EW7WH/6QDYQTwSBHw8UP0tyMyNbps8z+8Q5FmgH8vHxFljollei7t8eaPHYkk5rnVsXfTSQ4SjT3Ki6R/yfZ5BEnJidV+OTY4jtwp6TKE+kf6ioudhBQQXHEpufZoZaVaTZXTiIGuNSUBDlZ8hnbIS8ou6QcKMly3uw16qq1jpI+sVrLhWSLFcfRqW774uvsXptcHlY3jyOYYvgNSnLk9DHpURDX2VPzmVnzh4qOFmePV/gjmpSqLQpV1/iNIt9g3DADVd6eBWCjpp7/eefKoA1yLf1v3cLqoz1NFJZDj+xZBAIGNokT1IaiTnENcvwwJWL3xKUl+n4thAe+UgHXKJZ2an3jTF5IKjCZK3wFTIHqnkVBqLbYTnNr8t764mZT1/9wh4OKLf46TVR2knmcx1cuUtGr3Sewy3daul0qF4ixlI8qx00gkAJPhMSgdD9NphN7vd38cFIdIrhJ257ibJH98P6LFTvtBlJtLNk0e8UNLU9gvqtKe+mlotbHy1WlN3l1P02b370hBTcnBA0JVykYqIO2Yux+kvP"},{"id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"API接口文档","description":"api-documentation","prompt":"创建GEO平台的完整API接口文档。详细记录所有RESTful API端点,包括HTTP方法、URL模式、请求参数和响应格式。文档化认证接口的JWT令牌管理、用户注册登录和权限验证机制。说明查询管理接口的任务创建、编辑、删除和执行功能。详细描述引用数据接口的数据查询、统计分析和上下文提取功能。文档化报告导出接口的CSV格式生成和数据导出流程。包含错误处理、状态码说明和API使用示例。","order":7,"progress_status":"completed","dependent_files":"backend/app/api/subscriptions.py,backend/app/api/admin.py,backend/app/middleware/rate_limit.py,backend/app/middleware/logging_middleware.py,backend/app/services/citation.py,backend/app/api/auth.py,backend/app/api/queries.py,backend/app/api/citations.py,backend/app/api/reports.py,backend/app/api/deps.py","gmt_create":"2026-04-22T18:56:47.083629+08:00","gmt_modified":"2026-05-23T15:17:24.331381+08:00","raw_data":"WikiEncrypted:rEJA+fDSevRLFPlWlcH+C02eArPzlHQTxpYkpRmh+m+CmPwrZOHSqyEVvpFbcfuzlCdXmMyG1qoekj03JLnUhMCX8p4fjuyWVCjGyWgOqZfEYH4zqWamc16YOPdK+sCFQ4QmdrKW6cFcIs/JSz1BcE42L6PRCsFSdjC3x3Ir2kmeZ2xCyI4DTuIg5MWkYlr15jZuzLH5rMyvHib5uxo2LCklVn7i/8Yc6NLOW0AIHuLJGKU9hVU2nes18OolWvbkowwiJKV4MSqSrfUSL53HCd6IbvHajavu3hulkI00H4b/6Rkqq/mkJOEzBVSWXMI2Vj0Ww7mlzTkfkOv9v5Kp1CMC2qupcuFy78Q2J8fnj+tjDbvXOrkAe3LGWo59kGJXRS+LdWUjxsPwbaItkh9PFj2MOBQJ4dj38tLJ7OTH8Zag/VQP1Rr0yLqacQC0kduxAW/GKP5mj949etgdOr5Lsjt2hG9a/1bqVl7DWYX88aeyobv3qSg0/o/486gC040fYXNi3RFhZJev7cFLhxmkWPUFqKblmvIDwS5eDfYnWF4VVACVcqUVKWN/0V1whA2/u83e0nSdQLHU6gs1dAadBeJ0WvtCalaRzumPYSlz4Aw8pywfTE9u5GXpaONFFjCfgFuf6Mm3qpvL8InOKs1DhtGavpj+3P8MaFERk72a/Gb08fD1Ri60LsgMXjD5XdSw7IDRukJVTBRP80/vYYdNlDoeuM6uHvxuORxFCZNsTmC6PSerCo3AGnfpERUDzSV+ejU1fSrOc18pronb4I2lfIHjNpr3mjVLfnNEbsMRu/VHtk9lrPlkd3RxYRlC76W8XAK1cJr8Q6qtOz7qkNAs4W5VZoSO+6QAec2P5ej0aUJ0xR0Z1ZZhFyYPQE0VCrvcKSUJgeHUhcoBWbkPuxmk1l0FC4+Cu8JOksLcMRzb/2trJowZ57fQA7N/3YYOKlKW7wFqNXNJQ2djP2A5WflT9OL22/D0Py4o2wLDr7vtXv/4E2A0YJAPcqdwbeeYHN8Cika4GiA0Z48TomRK5PEPSop0NRekjHc2q3gppQK0+Pwy8GM0JOO04VeLCsbRKwjCrIB9+B9ciiBEDh2F/9+OxmySWZVKQB32NFozE4bT00ufcsFWApvwewZkiqUTWBaDjTrXxm1AnewI+T+/bLaY+m6Lr4yGO7jAuUDYkTSVT+IVNFX9ep2FVdMUqZFYp6+Vukj3nVwL8lRaG8zJaJ5TxxiB7grWdRXzaNT5CJlkTSEdFBkExAkNik1S4Xhfs2uU+BSvjZTzB7gOZKEYhjkV5m707rsT75hYFqeRLdIaCSWxZzHIHHTCxOfrAncP+2EkLHjP8bWAOjhdABT3djMsTSgm15W9NG8oAayRIoAE6M/ZAizrqiaAAKxQFAthKpGNTZZfdHNbxIfhk+D65kW8zTuk1aWN2k1ktFAc/sjQplPFkr/rY9K0PiBMFlXrye60kFAtFxjRpPUbtuRr3sMdJjPiHxB/bIi9XODVl9m7eyjDeTZFKmmxzafzNT9VP+YpBSy4QdKXaZkR219fdyhs52iRnGXP+9Phy6uUEh650InWE9CNFGZMSTRPpUkn9xJq/mVLJ667r9W0/aAs7ETC4g=="},{"id":"fc6f24c3-594e-4153-854f-19250834eeb1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"测试策略","description":"testing-strategy","prompt":"创建GEO项目的测试策略文档。详细说明Pytest测试框架的配置和使用方法,包括测试夹具、模拟对象和测试数据管理。文档化单元测试的实现,包括认证模块、引用引擎、查询处理等功能的测试用例设计。说明集成测试的策略,包括API端到端测试、数据库测试和系统集成测试。提供测试最佳实践,包括测试覆盖率要求、持续集成配置和测试环境管理。包含测试调试技巧和性能测试方法。","order":8,"progress_status":"completed","dependent_files":"test_output.txt,tests/test_business_flow.py,tests/test_scheduler.py,tests/,tests/conftest.py,tests/test_auth.py,tests/test_citation_engine.py,tests/test_citations.py,tests/test_queries.py","gmt_create":"2026-04-22T18:56:47.083879+08:00","gmt_modified":"2026-05-23T15:16:36.35803+08:00","raw_data":"WikiEncrypted:Xd2Zu8BM8p49theGlFJHkHqkA5ycuMpwkltd7rjxfkZm5u2F/OCOa2rxC3NxLrZDZf5D15q4Vh8tHCK9cPrOS/yjJEFoGKYx888+pCfJVQGvOvV8lbxJ/fNWDqo3ccIMDBY5poew3y/74L1tz0L9vjHRBLPVQADCR3UfTk94UBhlYGXamKDS74D8TgPqiuz1dVhmkX95unpFQiGQxCgxeV/sDgwTl7DYpnPy4VqFJbcPHD2Xvv828icOoxqz7hWaOp/65B5Vcn9P4LVk7dQmHzrLBdrDLBe+5Rv6mDD3+Rqrv3ZX+1v7tJ1dnmaQ2ZF8tE9ttI6ENeaFys0BrcucTSrsbSDtmFINzGh/aW0G3Q/YRtNfmkC9t+R8wRSnAgYadYSkUuNTVWQRRs4JxAcn+cHODObsEdp79EwDCqcLktVlpNaLJ//B0sOyLQA741MiLH5iM6tglYaOoQ48Ydyw7Fp5U9agWwgK7yZO7REk4ZB9U+juDzjf+qUHyjIVlXUxJXg7ATsy4euCmDpjyxJGRH7Z89wWkOotsSC3igqSM391kOqbzl9P5ZiruYliru20PndDwtXbJQ0jcvvKJsK3RkIYX0ml7BOL9H7Y16TL1Jwc6DVcRkwWQ4IEKG1fJhqYcb4WI/vPDD1jIhHBe6O5VAZtPPA+SIpYJg8+/qf0FQY73EPqWe0jPuc6I2jyN7UbjUMHRAeb0sVvj18qVYb4E+KKwNZyuAs+0SvTk/nTgqFPdNrOZ923/jnJTNt2Df1p89NDS0NGeHobiC4XD8koxe9vshUUdeDjXIopttcYBg4LcWAudoq8OO07eB6xiqn/MwXPaZySdWrqr3bh2xxxaQPR/NTrfrBkN+81NO784cJEkYHfSfUzIqhLhTTNEQpfl12WDM+GnbHWCcyWuN2dvZ6Op/ZCpLO+cQhZnXFPILnCzFf8DyNrbD3niQYcOC6H1nFlaGSmx57lswjyX14vwqOB+yNR8n+xG1a7JwxscBYaNQG5kvfLaJJKpxIdSB2YIKrIwImPHtzTI1Qahh3MfLtqI99aH9p/1LMaKJQsASKr1Ja1X3dO+ZpIiQRTeDR/jdWnzBA7Hk9SjB6ALHJhLYTutqKVkeIL08U9HNeWn3BFwCthEXMHapg0Vh/guoIq1j28UwzPkqMcSynuv98uyhHfUgRbOWQ9WTDis8gPn2jxpoCZyVCAxOTfF+67GDoTn6smJmqHIkQkMjrxLVZE3FfMtXHAcZ2kG9DC1aLVFNm64bP9X/W11dT6vm5SkabIiu1AzYuZDce+Rbg73WaCMrv4sXmBpNYhYUkLRj4gwNEFSd+eOJ/GS6MZSkA7p6A73OY1PHXlRnFrcLN10/XzFaPAM8L3h4WmqYoxFNJPTx5hRuwX2MfiwZgZlaICfBuO"},{"id":"803bfef4-3985-477e-a61c-915a246d0061","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"部署与运维","description":"deployment-operations","prompt":"创建GEO项目的部署与运维文档。详细说明Docker容器化部署的完整流程,包括镜像构建、容器编排和环境配置。文档化生产环境的部署策略,包括Nginx反向代理配置、SSL证书管理和负载均衡设置。说明监控和日志管理方案,包括应用健康检查、错误追踪和性能监控。提供运维最佳实践,包括备份策略、安全配置和故障恢复流程。包含CI/CD流水线配置和自动化部署方法。","order":9,"progress_status":"completed","dependent_files":"docker-compose.yml,backend/Dockerfile,frontend/Dockerfile,backend/requirements.txt,frontend/package.json","gmt_create":"2026-04-22T18:56:47.08417+08:00","gmt_modified":"2026-05-23T15:19:55.903951+08:00","raw_data":"WikiEncrypted:XJiAh4Py4zdOGBbpygpFvP2f+xZrLdOVjdkWVTkd9gNZugMlEc15uGPZP/rOKei73finM/xzqTLj8dzUBfzhoso2Si3u9jWEKBhnERW9MW+jwXRrsLHgJ8/WEK9QHKbGl5gw2ib+bp5Pwa3apjwkDwN5hBQC4+vjqTVbQlLqK0Ec0taA3iua9wbtV8nY5tSgUrtYRdRqzYd0Em0JPfrNHfDBKqGbhIQEUICLTk1cXUkVNLZKNUKN2gJ7Q9NlheaerlKDVWNp7Mt5ZecokwsM47Wiey36A1pO4kEQC1jZn/NgxPB30sC1zrjdI9mVBfMdWMqeNtBsE5zL8M/Ix6ikOpjqm9PfHkvZrqrO0WGPE73wyU+o4Y9pOZBbS3LmrWZVjTFjhJpbRCtc6yjqX6cnon067zrHSs6jN3OwPdIL2QlEK0kfeK3Xd7Gmgpciptuo4sAetP+NGr7L8qUmtZNA0LJj+G+6vT1ErRdauMsNrnHaWSPvz8j85Gi0LZxFyvHiY0jh+p4llPzjOdvFBF+0Js0sQE70kxor3NCunmf0YkA1+Xn4UhiJnQTVC6FSA/n6ZHmiyK5XJ9Ca3IDAnYdxZAZ43BodukbTg81j6fHPL03zHVg3nunXKZc11hTWaTweKhrfSzff+W7/183vgUybq811/AaSC/wXh483Lj+/QHEYJCz5kUSnMkw5ZcBJM8WV4Nh1+68paKY2TnViG1OkbNXQar07qmeyz+1Qee5lVPriiiYAulSw4fc5w0tssZVrJXpDP+SseXKQDiqxEToU0cz3TdWLKEV9p8koKUGYYAU5q8rP03IsmocbgqvSQf6RJ/B905IWZ2UK2QQop28wF4NOBt395jw/7+LbLwMnmLw4RP67Z1ptgrZksi437IrZyhuOhAzO4cqml7FP+lVNfdYIsIi+BYAfow60IWKBkBg4j3Ljwhqxeggz6flWuRMtwcSGty7LRv6pNy9Q1ofyxZTDBkvFnRmJpBOKkgUxSZBwKLavC88mCLPet/b2LuLGcj7nMw4KW/xBxqt5eR3zI6OHs/6eYvLe0Qv9aln8WRnBJFXe9PtVPjlkCr4C/+liP+3QwiNS3+fSazJtX6pRe+3R4zzU4uVkLhoIc0lxDc5q7MUBUhnigZHESotAn/B8Y7izX/69qm2ZzZWIvwRMR25GjM6PgIz2eAFzsZb0Vmy2CuPE3r86A2/svEjBSnsIeag8jTo7oAclMCCqWKa1Av0kSrFyZug4OYkIoTnOOCCq+JPuuiRdX2BsIApIHHZv"},{"id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"开发指南","description":"development-guide","prompt":"创建GEO项目的开发指南文档。详细说明代码规范和最佳实践,包括Python代码风格、TypeScript类型规范和命名约定。文档化开发流程和工作流,包括Git分支策略、代码审查流程和版本发布管理。说明开发工具的使用方法,包括IDE配置、调试技巧和性能分析工具。提供新功能开发的指导原则,包括模块设计、接口定义和测试要求。包含常见开发问题的解决方案和故障排查方法。","order":10,"progress_status":"completed","dependent_files":"push_script.sh,frontend/tsconfig.json,frontend/tailwind.config.ts,frontend/.eslintrc.json,backend/requirements.txt,CONTRIBUTING.md","gmt_create":"2026-04-22T18:56:47.084469+08:00","gmt_modified":"2026-05-23T15:18:41.224011+08:00","raw_data":"WikiEncrypted:9b1XqHriaqPGsMtQmhzV28eiWwL8soWZUx4jD7Lpj1ZvEeRHqDXnLB57Wv0GJdW0bSai+es/AGcSLV4r5Y1zXQCgYNssGUbbdn66dv22fGk42xijVyio7TzEJPm2vZsrwpJe+/yfqkj5uigIlIv06GRfmEvdn6T8ivaGf4o8qPrbbaCqfb656Ecihx7i5F1ZXK+etNk5HJeheOAvl/WoiZD0TchF59yuuB06Rl/W0/sfm7xUtkC5QYYoo6qYsIuOIE9ynhoHFI2junjkQwS3m3E/W3kKHTNe57a56kaMBo2fa1in+LuWr0jPxfsXJWHwwN47eEs+neAYXoxz+AHzJxrd+FTvW8o+Jr7hmJjODk/1u5VGWqquek2DS33JHThmmD3ant8C85SI0QDd2Rez4xia2mCq+kIzwnOuORyodpDeIHYWrwbL0X6Q4KzwwZKXYBlWZH+PqiovtlIQpZ+FrabfOImECKTIsdYECFDGwvOvZdH09Kmi2TqBszsArbv/apEc8HtRyn3MbxlOmBZ3C86pepDzntKeY8OsRhZv1/EHc12+zlfgBxkzS7g3sZhf01vr2xPsYdFU6Zpts9eWNmMJAthuG+wyeYrGDXuGHQFbXa7Rhz/mWmDKqcUZcrGo2ScQwNuk19uCmQ5x7ZTM1iNSbKYWaJwW4jn9gG8sw9+saye/tFTCyDoaqyyumHT8s/aE3bvalg4fA4AE8RigKIlwzLKW7sZmL8sY6b3PBgIJB054DRRSUF/jEW24wPDgcW29SEG6MwyqEVCpBGvI1t7zhmmM6IRklQNvVzGaoQ5GkTDxAaMh5ULEbqPdmjMJkyTP8xtyLhrJz/UJRuvvFOpf2zyyHg8Do9zNEP/FNUbq2sjjMPwMUwZAVcU2jQvNyiUYJXLvzaYk7fSEr74I3YbU9XE+/dofBpCd8tPG/BmV09UZCVgI3UrSRYd+GcgziKhnbDf/UVR691bhj4lUBtNzyNM2AnUWoQN9IMyjpMEo6EDlTrIL6wqn36aRNqPibx1vbsAdFAwmJQbf0oVZ43AGDJde58EOtIh6QzXdY5yj+UYIl8iCXO0VtnMm79ouguB3g59SOTIbv6X/iFjQ3rvERX6pFPBI9GyKfhKQTwib98D+9pkHnU2n625WeukHx67ieQLvZ7pZLfqMYTEQvo80N0JfbAP4FNz4Mtuc7jpXm2JyV/tAI/Y4Lbx1KMUq2mDsZRamD6HWF61GEGr94VsrM8kFcf2RHb9C6Lt3EuKlasgwJqSnr8iO5oONILiT"},{"id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"扩展与定制","description":"extension-customization","prompt":"创建GEO项目的扩展与定制文档。详细说明系统的扩展机制,包括新增API接口、前端页面扩展和数据模型扩展的方法。文档化配置定制选项,包括环境变量配置、功能开关和性能调优参数。说明第三方集成的扩展方法,包括新AI平台接入、新数据库支持和新认证方式的集成流程。提供插件系统的使用指南和扩展开发的最佳实践。包含系统定制化的案例研究和实施建议。","order":11,"progress_status":"completed","dependent_files":"backend/app/workers/platforms/base.py,backend/app/models/,frontend/components/,backend/app/api/","gmt_create":"2026-04-22T18:56:47.085228+08:00","gmt_modified":"2026-05-23T15:26:10.260607+08:00","raw_data":"WikiEncrypted:LeuqUwl+gnRWd4pQx2elJJnaNsYdZ/J63Pw0fce9aNqmpJpPYIsQ5TrEOxu/uvHnQSFFKBmEUts4wkhM6Rw84oLNhVY4dAAe1SgbxUSAMBPaB14KY8PUqWIpdCEioEWmzsnVj7K/kD5jbg2km9CoQTfth8WHg/Y6a9BjIyCgjHAkN8xdYtoIZ019phFFwhiFZHTzwOMsaOLE4uNYhO/5VtM7enfDpbUkYkPKaI9O89GwD5CV1zTnlHpsmZpnGl/lWC/ucBfeyb0EAeKXW03W4in8q8jTKNJYPZnawgbDI9LGakgP1/F6i/T2CTB7vUWI3RvEcxDjIFn/g4Y9lrvxxRwi7tELxBj1tRN1UQ/UWC++syM1xNd8EqmIsChyPd/qyec4Cq8hwcS20hlCJ/A5b6lkkrCcVSybCKYh2rTwydQ0IyvDY4CBB/IkmGyuRiir9sLD7ikE6/pyC5puDhgPwf0C9dgMOcDm3Hprnsj2fNPGx5XiCghoWPOws5Nlqf8hLtlXGYO1rIG7QXzZHlSsqHr1Xx19ZR7PbU3xd5Lzgz9QlTbqVeTIyFnM4NPhSHICOwmIDlPFhO8Hb3uwgfAgq7DFiQNhSaVXFzWC6xw+ai66iwkC6IuqjxlW2zpJ/tRo15UZ7Jwwt5QajmUIgxHjERg7s/ccW7jYphuD4P4NjCD9aqveeWlujnM9OUglJ/BRS8lrVKjd11Po/t2FayPjpjAjoIfRK2r6GykToOAcBdnulkEeuVJetR9lR3/6iZf9fd8rTRiN99+R/b39s1UPSyCuJW3N5XzSOT7em2iCquEFIPw7Mb8cx147EY3dis458UKoEMmUIhD/IzxL9kk3dlp8ypRv0REsXkYWYNK9pBAZAE9RO0pAz/4KiHYRlw3tpR/h+QNQFjEIl26ntoyFpK0iCgQNwD+tloHz0YrpfvIk0syjsbZyEKBexmsMrvRO+d4/6Tjba1Z8sujKcvCI4XcS1cSjwJB8l3mOYlONmFTBXwqAUtoV+oAbWIQYk35NBDsxQtndMU5JI8CdBd2+qW8IUlgnGbOEwOoM4zKpLxsE22b+g2Mm4JpJ0pcDPFSGqgQKTO2P0/IoyjFU+6cBk8Xu/i9uBitDoXLU6kbntHlRM4BW+ndKIN0VsWVgq1LoKJFqyRl6uzvpbPLv7KjVuN7TwalTWG+XIPN7UW2iReTfVVTfvBftrXpVHqmJeRL1"},{"id":"8e3d62e8-ddbe-4820-bc41-7da9e91ea598","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"故障排除与FAQ","description":"troubleshooting-faq","prompt":"创建GEO项目的故障排除与常见问题解答文档。详细列举和解决常见的认证问题、数据库连接问题、API调用问题和性能问题。提供系统监控和诊断的方法,包括健康检查、错误日志分析和性能指标监控。说明调试技巧和工具使用,包括开发环境调试、生产环境问题排查和性能分析方法。包含常见错误代码的含义和解决方案,以及预防性维护的最佳实践。提供紧急情况下的故障恢复流程和应急处理方案。","order":12,"progress_status":"completed","dependent_files":"backend/app/main.py,backend/app/config.py,frontend/lib/api.ts,docker-compose.yml","gmt_create":"2026-04-22T18:56:47.085508+08:00","gmt_modified":"2026-04-22T19:04:06.13183+08:00","raw_data":"WikiEncrypted:CaKOW8OSSWs4aEYk06Hu0tuZET5JxbVXxA/4vFailoRiq8l6SCRMdp2PbHfZPheZXyPTAgE3AT8Ce8j9xPOCdJxNKAOstuOjZEIRRi9OOYwoluR4MUnob24X+IyLHwTgsJGf9uPY1LVFTI9RTQt8aG1cBHibaRNEJ8+DVkXJW/EDypOxFpOxDxlaCscMdiPRLwhr9V4vJqWV9j2rk1LjP2/M8SJJQ8hbaDoeLevKdECB+aEw9JrL9ycGW0dhxKxQLf/ril9zNHrvahlSXbVZSZ39dpBl57NdFcFaOYt+paf3O6hv3bCTAKGLTRnYa/IuAZ6Xa7YnhqaGQ684LKCBz6VySRNYVUCEvZotYHf1IQdWOj0zFzR7LEIEikIlZyKak++yTNYfbQyBEzye3g6YCmlh6VaVmtGIRzjOYpu0K1UftNcRa1mWnIMrB/Pqe9DpNTg+Yxo3ZHrPyv3ZAmrd8MqA+T+P+/NerCmFD3dRf94NLPP8KU7in+VSfEjVmdE0N+3OfntU+uvNL/kkOhyWNRUKYKFxbqdwCTKqv3Nchs73XyhfNRP7gPkR/stgnowCRnKWS4ncUEJDZTWVFID52kE8nH7Kq/yuB5bJxFX9AeUUaNSBgvMc5YNkq3vULFEqC1/N0bpU4r9+0/U/BcMktmNrRr1HnOIPl3QzwjIsT3j2lp4UXS3Qm4BZFJsh8MVLfgOIMbO1jbuGCXHl88T/rZOCNwf4q93vWo2HnOxDkbdICWgZ9dinRr85RkFQjNWlXdAk0XG8lQPotwJLvS+ZASOv1aWyL42jk/mTJcOU53PFT5rf3+WpVmhNWQGguZ0l04eubO4Va39c6h/+DNsl0OEAiozIMohEgz77qsD47Kf0KZMLnqL3o30TYXYamX/CP8+epBqSWgmzX/ETrrRl/1/JPkSDc//0VC8UmWBJAsdUdzyQh9v9iQddyIZ4MV1k4MGTJ6GwrUqVTszShZJVG80wDMLQvJGqJ0T5rH1P7kBaJ5nBnth822MBy7B1IhN6nDqtLhOJcqT8Qt6x8ODGFx1QMNBdS4lHq5IcRy+nZKiPP3V7uMuuFQsNNodTRhmNnuAliJACWS89hPiGroan2VkusxIu2DW8wdQ/3Z31mIn4cE3O3+Aq6lO+BEMAuYh5WkOEmGsF3cjX/zPPiuBSP7Vd2a9o6gPA7MBfneMWyqodMp6PKh7EG26gaKUaIGq6VkQobSAVfbLxmfIMW6cZ5STH4U1/A7gV2PeuWzwwEJz7axGVQIJ6A9geQevZvD/cnX6BQBuOMkdAOB6PApCpQA=="}],"wiki_items":[{"catalog_id":"1bb55e12-24c4-42cb-8f59-ddc303460d45","title":"项目概述","description":"project-overview","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"34e572eb-6fc8-4de7-8061-63783ef8be24","gmt_create":"2026-04-22T18:58:50.323135+08:00","gmt_modified":"2026-04-24T10:58:35.431256+08:00"},{"catalog_id":"e3ae8925-4862-4280-b85a-0b376841b15e","title":"快速开始","description":"getting-started","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"7f028ad1-e989-43ea-b945-c79c33e6f0e3","gmt_create":"2026-04-22T18:58:54.232866+08:00","gmt_modified":"2026-04-22T18:58:54.238013+08:00"},{"catalog_id":"7c2ac186-ec90-400a-ac1d-b3b7ca2f01d5","title":"后端系统架构","description":"backend-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"c7eb113b-b503-4d83-be7f-9ccf3350c9d9","gmt_create":"2026-04-22T18:59:20.999631+08:00","gmt_modified":"2026-05-23T15:24:02.350823+08:00"},{"catalog_id":"d907a8eb-795c-4060-9cdd-50d31cf39be3","title":"前端系统架构","description":"frontend-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"3af3bb9e-4d99-4dc3-b1ed-2686db385c26","gmt_create":"2026-04-22T18:59:54.989699+08:00","gmt_modified":"2026-05-23T15:22:58.592546+08:00"},{"catalog_id":"243a1a45-d31f-405e-a3b9-694d2fe617d5","title":"数据库设计","description":"database-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"ffbb970e-56e0-40ad-bd88-1a1e55482d96","gmt_create":"2026-04-22T19:00:15.762815+08:00","gmt_modified":"2026-05-23T15:19:23.714851+08:00"},{"catalog_id":"7416db23-312f-478d-8883-2fc3c41ac2e8","title":"任务调度系统","description":"task-scheduling-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"deb919cc-9541-4ed7-a581-ae2876ea67c2","gmt_create":"2026-04-22T19:01:21.979952+08:00","gmt_modified":"2026-04-23T15:20:09.061378+08:00"},{"catalog_id":"7e66719b-4a8a-484d-889d-10fdc76788bb","title":"AI平台集成","description":"ai-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"cfc48cde-e1c3-47f6-afe2-a6d7a8f4ab69","gmt_create":"2026-04-22T19:01:25.981164+08:00","gmt_modified":"2026-04-23T20:31:36.620216+08:00"},{"catalog_id":"dd12cc44-0c95-45d5-a726-e7b8bcf2531b","title":"API接口文档","description":"api-documentation","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"49915365-e38e-43b5-beac-6aa7d5a74cbb","gmt_create":"2026-04-22T19:01:28.269494+08:00","gmt_modified":"2026-05-23T15:17:24.331789+08:00"},{"catalog_id":"803bfef4-3985-477e-a61c-915a246d0061","title":"部署与运维","description":"deployment-operations","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"98909ecc-fceb-4ab7-a26f-741838eb2e50","gmt_create":"2026-04-22T19:02:23.847103+08:00","gmt_modified":"2026-05-23T15:19:55.904209+08:00"},{"catalog_id":"2148d7d6-25c4-497f-8894-c4eb7a0d2bd7","title":"开发指南","description":"development-guide","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"643984fc-5a57-498b-8f25-68cc318d9d82","gmt_create":"2026-04-22T19:02:27.517117+08:00","gmt_modified":"2026-05-23T15:18:41.224209+08:00"},{"catalog_id":"fc6f24c3-594e-4153-854f-19250834eeb1","title":"测试策略","description":"testing-strategy","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"b0c36b2b-bb03-4624-933d-c1f6a320b7ca","gmt_create":"2026-04-22T19:02:30.709013+08:00","gmt_modified":"2026-05-23T15:16:36.35829+08:00"},{"catalog_id":"7c3e3c0b-5d1f-4d64-99be-668041c6cd9d","title":"核心框架配置","description":"core-framework","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"f94da0b4-8a07-4de1-b0b3-d3b32a12c3c1","gmt_create":"2026-04-22T19:03:21.689103+08:00","gmt_modified":"2026-04-22T19:03:21.693211+08:00"},{"catalog_id":"b2bb2e3c-5661-497c-97dd-15bf6ee8b7d4","title":"扩展与定制","description":"extension-customization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"c5849940-e223-4222-be17-aa0a6cb36bc8","gmt_create":"2026-04-22T19:03:46.027426+08:00","gmt_modified":"2026-05-23T15:26:10.261496+08:00"},{"catalog_id":"8e3d62e8-ddbe-4820-bc41-7da9e91ea598","title":"故障排除与FAQ","description":"troubleshooting-faq","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"85306af2-0edf-42b8-b7ad-c03e769cb1e8","gmt_create":"2026-04-22T19:04:06.127415+08:00","gmt_modified":"2026-04-22T19:04:06.131953+08:00"},{"catalog_id":"bcaa04da-04e3-427f-ba01-847ad657e78a","title":"Next.js应用配置","description":"nextjs-app-config","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"c112a3f4-b0a1-4c4a-a325-e3ede8c90be6","gmt_create":"2026-04-22T19:04:47.356556+08:00","gmt_modified":"2026-04-22T19:04:47.361504+08:00"},{"catalog_id":"9e3d703f-f424-47f4-84df-b99873b93e5a","title":"项目介绍","description":"project-introduction","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2793782c-91c8-4052-b9db-39513426c736","gmt_create":"2026-04-22T19:05:00.372036+08:00","gmt_modified":"2026-04-22T19:05:00.376145+08:00"},{"catalog_id":"a06436ee-1678-4a51-bbf8-b0d0ac3456b9","title":"数据库架构","description":"database-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"d5c75004-b01b-416f-850a-4791c5489a32","gmt_create":"2026-04-22T19:05:13.619093+08:00","gmt_modified":"2026-04-22T19:05:13.624074+08:00"},{"catalog_id":"7fea5a24-e6de-4003-bc70-9dae6d8fdb25","title":"适配器架构设计","description":"adapter-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"37003fc0-1cf5-4264-996b-40807001875f","gmt_create":"2026-04-22T19:06:14.01196+08:00","gmt_modified":"2026-04-22T19:06:14.016291+08:00"},{"catalog_id":"b027f234-4ac5-4d6d-9b38-afc8054325f5","title":"单元测试","description":"unit-testing","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"8150ddbb-7aa9-48d0-9953-2ef55e4bcfd5","gmt_create":"2026-04-22T19:06:55.084551+08:00","gmt_modified":"2026-04-22T19:06:55.090188+08:00"},{"catalog_id":"940e5918-1689-4001-a284-44f2de75b8ee","title":"认证接口","description":"authentication-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"7c7564ee-7fe2-4555-8ff0-4ec1b757997a","gmt_create":"2026-04-22T19:07:12.352034+08:00","gmt_modified":"2026-04-22T19:07:12.356599+08:00"},{"catalog_id":"78288302-33bd-44f7-8b29-24f516c8b6bb","title":"调度器设计","description":"scheduler-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"a1cc822d-5382-431c-8c49-cf398fb5eb3c","gmt_create":"2026-04-22T19:07:22.166733+08:00","gmt_modified":"2026-04-23T20:33:30.132576+08:00"},{"catalog_id":"6406f42a-e10b-4a2b-84a5-0a21c1c759ea","title":"代码规范","description":"code-standards","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"13c568d2-dfa7-4d1b-81c0-dfef247cbb67","gmt_create":"2026-04-22T19:07:51.271116+08:00","gmt_modified":"2026-04-22T19:07:51.274241+08:00"},{"catalog_id":"a91fff3d-ec5e-43df-8176-22f0084109ef","title":"功能扩展","description":"feature-extension","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"d2c7157d-157f-4990-8f76-11f3ea5435f7","gmt_create":"2026-04-22T19:08:25.13644+08:00","gmt_modified":"2026-04-22T19:08:25.14088+08:00"},{"catalog_id":"e8ec6ac6-ad1a-4332-a7be-727b47d71233","title":"Docker容器化部署","description":"docker-containerization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"1ed0b482-3d6a-4bfd-af40-47a5d1f3e802","gmt_create":"2026-04-22T19:08:34.079807+08:00","gmt_modified":"2026-04-22T19:08:34.084736+08:00"},{"catalog_id":"c19260e2-5163-43d4-b35a-b48aae995f4a","title":"认证系统","description":"authentication-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"df661133-efbf-43fe-97c3-f581c81f47a7","gmt_create":"2026-04-22T19:09:25.676813+08:00","gmt_modified":"2026-04-24T11:02:17.638458+08:00"},{"catalog_id":"9b71fe02-5927-4a19-8db8-66eb129ecd9a","title":"认证系统前端实现","description":"auth-system-frontend","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2b32ec11-d228-42c0-9232-103ba7e44f71","gmt_create":"2026-04-22T19:09:48.743111+08:00","gmt_modified":"2026-04-22T19:09:48.747746+08:00"},{"catalog_id":"b80dc237-1a6a-401f-9f4d-14190edebcdd","title":"技术栈","description":"technology-stack","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"e23bd86e-b4ac-40eb-b1c1-38d929fd5419","gmt_create":"2026-04-22T19:09:54.21211+08:00","gmt_modified":"2026-04-22T19:09:54.216205+08:00"},{"catalog_id":"7e5c3b8e-5aa3-448d-ae52-d5a96a413b0b","title":"表结构设计","description":"table-schema-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"c3fa653f-8dd7-41fe-8c2e-8b60adbf70f4","gmt_create":"2026-04-22T19:10:23.573187+08:00","gmt_modified":"2026-04-22T19:10:23.576944+08:00"},{"catalog_id":"cc7a1f1b-c70e-4c61-bfbc-6dc408a12ff2","title":"查询执行流程","description":"query-execution-flow","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2fc79486-ec65-4533-860a-89c8877c2ea0","gmt_create":"2026-04-22T19:11:29.34722+08:00","gmt_modified":"2026-04-22T19:11:29.353951+08:00"},{"catalog_id":"fec685a0-c9bb-4048-baf4-40b56b2aa29c","title":"集成测试","description":"integration-testing","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"8c17b44f-1586-459b-a83d-c9b961cd2142","gmt_create":"2026-04-22T19:12:37.811472+08:00","gmt_modified":"2026-04-22T19:12:37.820956+08:00"},{"catalog_id":"9fe32b83-3697-4939-8b10-524f5ed3e65e","title":"Kimi平台集成","description":"kimi-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2126339b-b0f5-4152-924b-cbe028cd0c39","gmt_create":"2026-04-22T19:12:57.009145+08:00","gmt_modified":"2026-04-23T20:35:18.737804+08:00"},{"catalog_id":"b10c2334-a850-471a-9851-a1c698e3a485","title":"查询管理接口","description":"queries-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"74d3018f-4e23-4687-8bf4-7fb403f479f7","gmt_create":"2026-04-22T19:13:13.111099+08:00","gmt_modified":"2026-04-23T20:33:57.632097+08:00"},{"catalog_id":"0c1d3542-92cf-4796-8dba-82caf2f7b361","title":"开发流程","description":"development-workflow","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"222a9371-45c1-4e0d-b1da-e8ada1c501c2","gmt_create":"2026-04-22T19:13:23.079488+08:00","gmt_modified":"2026-04-22T19:13:23.082539+08:00"},{"catalog_id":"109a8fb1-6619-4bc7-8481-e28cc2127d24","title":"生产环境部署","description":"production-deployment","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"26f80935-eac2-44ee-bcdb-d6a79c537750","gmt_create":"2026-04-22T19:13:58.693673+08:00","gmt_modified":"2026-04-22T19:13:58.69756+08:00"},{"catalog_id":"4d5ac6d7-8812-414b-b8df-68574cc36d7d","title":"配置定制","description":"configuration-customization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"e1e0bd0e-01b3-4543-9781-d9beb32b9a57","gmt_create":"2026-04-22T19:14:17.837895+08:00","gmt_modified":"2026-04-22T19:14:17.84356+08:00"},{"catalog_id":"159f2ccf-71b7-4d1b-a4c4-c15b23a4126e","title":"API接口设计","description":"api-design","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"11936bb5-374f-40f4-bb53-b75264fc4b9d","gmt_create":"2026-04-22T19:15:14.073829+08:00","gmt_modified":"2026-04-22T19:15:14.079089+08:00"},{"catalog_id":"9cc59a5a-f597-4707-b994-b6c49514d553","title":"页面组件设计","description":"page-components","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"ba0390b3-c249-4e92-a3c8-6820343aeda9","gmt_create":"2026-04-22T19:15:16.958138+08:00","gmt_modified":"2026-04-23T15:19:43.818584+08:00"},{"catalog_id":"f70f5d9b-d7c7-4dc6-b36a-5f4508e6acaa","title":"系统架构","description":"system-architecture","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"70b3948e-f456-42d2-b7ad-a0097ad5ee5f","gmt_create":"2026-04-22T19:15:17.448445+08:00","gmt_modified":"2026-04-22T19:15:17.452857+08:00"},{"catalog_id":"816a2805-76c9-4f32-a3cf-96428208081e","title":"数据模型","description":"data-models","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"262a3941-fdc6-46b0-b767-be40aa9d5761","gmt_create":"2026-04-22T19:16:35.087998+08:00","gmt_modified":"2026-04-23T15:21:46.785271+08:00"},{"catalog_id":"64cbb894-755f-47b5-854e-c26c7821e9b2","title":"文心平台集成","description":"wenxin-platform-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"fab60eaf-9652-4cb5-9f9e-0525caa62d63","gmt_create":"2026-04-22T19:16:36.921828+08:00","gmt_modified":"2026-04-23T20:31:50.506906+08:00"},{"catalog_id":"412f8cb5-54c1-4f32-8966-fa0e5e75bbca","title":"性能优化","description":"performance-optimization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"d8e2cef5-37e6-44e7-8a7b-9bd365b82a72","gmt_create":"2026-04-22T19:16:37.806188+08:00","gmt_modified":"2026-04-22T19:16:37.81795+08:00"},{"catalog_id":"2f7fa0ab-cd3d-4f45-a1c1-389d5a0c2561","title":"开发工具","description":"development-tools","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"979be617-a83d-4db9-b73e-38581348f8c1","gmt_create":"2026-04-22T19:17:43.348035+08:00","gmt_modified":"2026-04-22T19:17:43.3539+08:00"},{"catalog_id":"40ac97e8-7ef0-4198-82d7-d2e332be9d34","title":"测试最佳实践","description":"test-best-practices","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"05e59a75-d52f-42e1-a924-f6a32f06f2fe","gmt_create":"2026-04-22T19:17:48.811042+08:00","gmt_modified":"2026-04-22T19:17:48.815559+08:00"},{"catalog_id":"41a414d2-e13a-497c-8a03-212624dbf5fe","title":"引用数据接口","description":"citations-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"737f8d6c-bd8f-4c11-b142-71a400423323","gmt_create":"2026-04-22T19:18:18.048509+08:00","gmt_modified":"2026-04-22T19:18:18.055466+08:00"},{"catalog_id":"2713d5c6-c6b0-4a38-83f6-56940c2bf695","title":"监控与日志管理","description":"monitoring-logging","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"eb1288f7-5ea1-413a-8f54-4f870306d14d","gmt_create":"2026-04-22T19:18:41.294736+08:00","gmt_modified":"2026-04-22T19:18:41.773932+08:00"},{"catalog_id":"c8a468af-2982-4d9c-82c0-313b5d2ee89c","title":"第三方集成","description":"third-party-integration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"e9a02c86-236b-49cb-bbed-9462ee123c04","gmt_create":"2026-04-22T19:19:17.34688+08:00","gmt_modified":"2026-04-22T19:19:17.362503+08:00"},{"catalog_id":"9eee7fab-6cd9-4ef3-9415-2f8137f1d199","title":"数据模型设计","description":"data-models","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"23ad3419-5473-4e2c-ac87-d9715090279d","gmt_create":"2026-04-22T19:19:19.260533+08:00","gmt_modified":"2026-04-22T19:19:19.282116+08:00"},{"catalog_id":"f210509a-2381-46fe-8c22-0ed768e6ca70","title":"数据库迁移","description":"database-migration","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"7c0201f7-9e02-4cba-9ee1-81c3477f049a","gmt_create":"2026-04-22T19:20:15.023549+08:00","gmt_modified":"2026-04-22T19:20:15.06665+08:00"},{"catalog_id":"d9e45b2a-6443-4a9b-8ed3-4c3c04773772","title":"UI组件库","description":"ui-component-library","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"760610d4-dff6-4c6d-831f-7c9078db86a6","gmt_create":"2026-04-22T19:20:16.20858+08:00","gmt_modified":"2026-04-23T15:22:23.574113+08:00"},{"catalog_id":"178b681f-d013-44b7-aef8-dee7ca8c22a9","title":"核心功能","description":"core-features","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"1c4316a1-f1d7-46da-bcfc-ea2fa0c56110","gmt_create":"2026-04-22T19:20:37.644038+08:00","gmt_modified":"2026-05-23T15:23:21.994326+08:00"},{"catalog_id":"ac0658da-7670-4e41-9e57-02d9d0d50680","title":"报告导出接口","description":"reports-api","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"ae62f4a8-8840-4c8e-9a42-3373370299ff","gmt_create":"2026-04-22T19:21:24.241821+08:00","gmt_modified":"2026-04-22T19:21:24.246484+08:00"},{"catalog_id":"aad61788-1dc9-4682-b743-47188d7aecb6","title":"引用检测算法","description":"citation-detection-algorithm","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"00359e45-209d-4be3-8795-50dea52bdba1","gmt_create":"2026-04-22T19:21:33.106655+08:00","gmt_modified":"2026-04-22T19:21:33.125906+08:00"},{"catalog_id":"7cb1d921-44ed-4e22-8bf9-baba7ff8b7c7","title":"新功能开发","description":"feature-development","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"422c46b3-e69c-4023-a878-411a48ae182f","gmt_create":"2026-04-22T19:21:46.910999+08:00","gmt_modified":"2026-04-22T19:21:46.916175+08:00"},{"catalog_id":"c45e66b9-1ca0-41da-a796-6b98f394faa1","title":"运维最佳实践","description":"maintenance-operations","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"aa6db9b6-71e1-4497-a0e2-f3ff25358d3a","gmt_create":"2026-04-22T19:22:39.442855+08:00","gmt_modified":"2026-04-22T19:22:39.447035+08:00"},{"catalog_id":"bfca5ffe-8905-4ac2-a0a3-8e4dc43533b1","title":"数据可视化","description":"data-visualization","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"a40267bc-925a-4364-a01f-b96d3df60aea","gmt_create":"2026-04-22T19:23:03.398982+08:00","gmt_modified":"2026-04-22T19:23:03.405853+08:00"},{"catalog_id":"05214c1a-d804-4f3c-9048-20ba4de3be0f","title":"引用检测引擎","description":"citation-engine","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"19e75845-5147-4aeb-90be-16f3aa270465","gmt_create":"2026-04-22T19:23:12.049419+08:00","gmt_modified":"2026-04-23T20:33:37.372858+08:00"},{"catalog_id":"b32b024e-2d06-45c8-94c2-a07fd25ab9b3","title":"快速开始","description":"quick-start","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"7e679d62-c415-4d6a-a7e5-d41d00e0ed69","gmt_create":"2026-04-22T19:23:49.794133+08:00","gmt_modified":"2026-04-22T19:23:49.797304+08:00"},{"catalog_id":"850fc702-3eb6-45b4-acd2-ae87fec1f4f1","title":"工作器系统","description":"worker-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"83fe6837-7874-4467-8114-103062f15f58","gmt_create":"2026-04-22T19:24:30.524061+08:00","gmt_modified":"2026-04-22T19:24:30.529283+08:00"},{"catalog_id":"fda0598d-7e92-4b8b-be52-92ae63c3cd98","title":"API客户端","description":"api-client","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"7bd2c461-81b0-48e8-8cb3-b4b14305806d","gmt_create":"2026-04-22T19:24:50.482622+08:00","gmt_modified":"2026-04-22T19:24:50.486476+08:00"},{"catalog_id":"15d6170d-716c-4d2a-833d-81211a59027c","title":"平台适配器扩展指南","description":"platform-adapter-extension","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2632a6f9-774e-4a91-94da-a984bdb20758","gmt_create":"2026-04-22T19:25:18.714623+08:00","gmt_modified":"2026-04-22T19:25:18.720105+08:00"},{"catalog_id":"a232faa5-28b0-4235-8ad4-b082fd226e69","title":"订阅管理系统","description":"subscription-management-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"ec2f1708-d31e-42bb-8959-fa405db7d6da","gmt_create":"2026-04-24T11:04:05.337544+08:00","gmt_modified":"2026-04-24T11:04:05.339776+08:00"},{"catalog_id":"9ac86c99-3b7e-4745-bc95-9586153d616e","title":"管理员仪表板系统","description":"admin-dashboard-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2059d1cd-98a3-4b7f-b29b-69acf8a0d751","gmt_create":"2026-04-24T11:06:01.087669+08:00","gmt_modified":"2026-04-24T11:06:01.089977+08:00"},{"catalog_id":"d54446b1-5984-4fe6-8fc1-ad0322ab7914","title":"安全增强功能","description":"security-enhancements","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"d474a7a6-e056-4456-ba79-4aedbb7add58","gmt_create":"2026-04-24T11:07:19.926098+08:00","gmt_modified":"2026-04-24T11:07:19.927668+08:00"},{"catalog_id":"d645182f-1eaa-4439-854c-0437806ceebb","title":"PDF报告系统","description":"pdf-reporting-system","extend":"{}","progress_status":"completed","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","reference_count":0,"id":"2d7c030d-7b82-418c-9a16-67b067cac93c","gmt_create":"2026-04-24T11:08:42.186525+08:00","gmt_modified":"2026-04-24T11:08:42.188311+08:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n\n# GEO 平台项目全面分析\n\n## 1. 项目介绍\n\n### 目标与愿景\nGEO 平台是一个基于人工智能技术的学术查询与引用管理系统,旨在为用户提供智能化的品牌引用检测和数据分析服务。该项目通过集成多个AI平台,实现对网络内容中特定品牌引用的自动检测和统计分析。\n\n### 核心目标\n- **智能引用检测**:自动识别网络内容中对特定品牌的引用情况\n- **多平台集成**:支持多个AI平台的数据获取和处理\n- **实时监控**:提供定时查询和实时更新功能\n- **数据可视化**:通过图表展示引用趋势和统计数据\n\n### 目标用户\n- 学术研究人员\n- 市场分析师\n- 品牌监测机构\n- 内容创作者\n\n## 2. 技术架构\n\n### 整体架构设计\n\n```mermaid\ngraph TB\n subgraph \"前端层\"\n FE[Next.js 前端]\n UI[React 组件]\n Auth[认证系统]\n end\n \n subgraph \"后端层\"\n API[FastAPI API]\n WS[工作器]\n SCH[调度器]\n end\n \n subgraph \"数据层\"\n DB[(PostgreSQL)]\n RD[Redis 缓存]\n end\n \n subgraph \"AI平台\"\n WX[Wenxin 平台]\n KM[Kimi 平台]\n end\n \n FE --\u003e API\n UI --\u003e FE\n Auth --\u003e FE\n API --\u003e DB\n API --\u003e RD\n WS --\u003e WX\n WS --\u003e KM\n SCH --\u003e WS\n API --\u003e WS\n```\n\n### 核心设计模式\n- **分层架构**:清晰的前后端分离和业务逻辑分层\n- **异步编程**:基于 asyncio 的高性能异步处理\n- **依赖注入**:通过 FastAPI 的依赖系统管理服务\n- **适配器模式**:统一不同AI平台的接口调用\n\n### 系统关系图\n\n```mermaid\nsequenceDiagram\n participant U as 用户\n participant F as 前端\n participant B as 后端API\n participant S as 调度器\n participant W as 引用引擎\n participant P as AI平台\n \n U-\u003e\u003eF: 发起查询请求\n F-\u003e\u003eB: HTTP请求\n B-\u003e\u003eS: 触发查询任务\n S-\u003e\u003eW: 执行查询\n W-\u003e\u003eP: 调用AI平台\n P--\u003e\u003eW: 返回结果\n W--\u003e\u003eB: 处理后的数据\n B--\u003e\u003eF: 响应结果\n F--\u003e\u003eU: 展示数据\n```\n\n## 3. 关键实现\n\n### 主要入口点\n\n**后端主入口**\n- `backend/app/main.py` - FastAPI 应用主入口,包含路由注册和中间件配置\n\n**前端主入口**\n- `frontend/app/layout.tsx` - Next.js 应用布局组件,包含全局样式和提供者配置\n\n### 核心模块\n\n**数据库配置**\n- `backend/app/database.py` - SQLAlchemy 异步数据库配置和会话管理\n\n**配置管理**\n- `backend/app/config.py` - Pydantic 设置类,管理环境变量和配置参数\n\n**工作器系统**\n- `backend/app/workers/scheduler.py` - APScheduler 定时任务调度器\n- `backend/app/workers/citation_engine.py` - 引用检测引擎核心\n\n**API 路由**\n- `backend/app/api/auth.py` - 用户认证相关接口\n- `backend/app/api/citations.py` - 引用数据相关接口\n- `backend/app/api/queries.py` - 查询任务相关接口\n\n### 配置方法\n\n**Docker 配置**\n- `docker-compose.yml` - 多容器部署配置,包含数据库、缓存和应用服务\n\n**依赖管理**\n- `backend/requirements.txt` - Python 后端依赖包\n- `frontend/package.json` - Node.js 前端依赖包\n\n### 外部依赖\n\n**后端关键技术栈**\n- FastAPI + Uvicorn:高性能异步Web框架\n- SQLAlchemy 2.0:异步ORM框架\n- APScheduler:任务调度框架\n- Redis:缓存和队列存储\n- Playwright:浏览器自动化\n\n**前端关键技术栈**\n- Next.js 14:React 框架\n- Radix UI:可访问性UI组件库\n- Recharts:数据可视化图表\n- Tailwind CSS:CSS框架\n\n### 集成点\n\n**AI平台适配**\n- `backend/app/workers/platforms/kimi.py` - Kimi AI平台适配器\n- `backend/app/workers/platforms/wenxin.py` - 百度文心平台适配器\n\n**认证集成**\n- `frontend/components/providers.tsx` - NextAuth.js 认证提供者\n- `frontend/lib/auth.ts` - 前端认证工具函数\n\n### 组件关系图\n\n```mermaid\ngraph LR\n subgraph \"认证模块\"\n AUTH_API[认证API]\n AUTH_FE[认证前端]\n NEXT_AUTH[NextAuth集成]\n end\n \n subgraph \"查询模块\"\n QUERY_API[查询API]\n QUERY_FE[查询前端]\n SCHEDULER[调度器]\n ENGINE[引用引擎]\n end\n \n subgraph \"数据模块\"\n MODELS[数据模型]\n DB[(数据库)]\n REDIS[(Redis)]\n end\n \n AUTH_API --\u003e MODELS\n QUERY_API --\u003e MODELS\n ENGINE --\u003e MODELS\n AUTH_FE --\u003e AUTH_API\n QUERY_FE --\u003e QUERY_API\n SCHEDULER --\u003e ENGINE\n ENGINE --\u003e DB\n ENGINE --\u003e REDIS\n AUTH_API --\u003e DB\n QUERY_API --\u003e DB\n```\n\n## 4. 核心功能\n\n### 功能概览\n\n**用户管理功能**\n- 用户注册和登录认证\n- JWT 令牌管理和会话维护\n- 用户权限控制\n\n**查询管理功能**\n- 自定义关键词查询\n- 多平台AI数据获取\n- 定时任务调度\n- 查询历史记录\n\n**引用检测功能**\n- 品牌引用自动检测\n- 置信度评分算法\n- 竞争品牌识别\n- 文本上下文提取\n\n**数据分析功能**\n- 引用趋势图表\n- 平台对比分析\n- 统计报表生成\n\n### 实现亮点\n\n**智能匹配算法**\n- `backend/app/workers/citation_engine.py` - 实现精确匹配、别名匹配和模糊匹配三种策略\n- 支持中文和英文混合文本处理\n- 提供置信度评分和位置信息\n\n**异步任务处理**\n- `backend/app/workers/scheduler.py` - 基于 APScheduler 的异步任务调度\n- 支持多平台并发查询\n- 完善的任务状态跟踪\n\n**响应式前端界面**\n- `frontend/app/(dashboard)/` - Next.js App Router 页面组织\n- `frontend/components/charts/` - 数据可视化组件\n- `frontend/components/ui/` - 可复用UI组件库\n\n### 功能架构图\n\n```mermaid\nstateDiagram-v2\n [*] --\u003e 用户认证\n 用户认证 --\u003e 查询管理: 登录成功\n 查询管理 --\u003e 任务调度: 创建查询\n 任务调度 --\u003e 引用检测: 定时触发\n 引用检测 --\u003e 数据处理: 获取AI结果\n 数据处理 --\u003e 结果展示: 处理完成\n 结果展示 --\u003e 查询管理: 新查询\n 结果展示 --\u003e [*]: 退出系统\n \n state 查询管理 {\n [*] --\u003e 创建查询\n 创建查询 --\u003e 编辑查询\n 编辑查询 --\u003e 删除查询\n 删除查询 --\u003e [*]\n }\n \n state 引用检测 {\n [*] --\u003e 平台查询\n 平台查询 --\u003e 品牌匹配\n 品牌匹配 --\u003e 竞争检测\n 竞争检测 --\u003e [*]\n }\n```\n\n## 5. 总结与建议\n\n### 项目架构特点\n\n**架构优势**\n- 清晰的分层设计,前后端职责明确\n- 异步编程模型提升了系统性能\n- 模块化设计便于功能扩展和维护\n- 完善的错误处理和日志记录机制\n\n**技术亮点**\n- 基于现代技术栈的全栈开发\n- 智能算法与工程实践的结合\n- 完整的开发到部署流程\n- 良好的代码组织和文档规范\n\n### 改进建议\n\n**性能优化**\n- 考虑引入连接池优化数据库连接\n- 实现缓存策略减少重复查询\n- 添加限流机制防止API滥用\n\n**功能扩展**\n- 增加更多AI平台支持\n- 实现批量查询功能\n- 添加导出数据功能\n- 增强搜索过滤条件\n\n**代码质量**\n- 完善单元测试覆盖率\n- 添加API文档自动生成\n- 实现更详细的错误处理\n- 优化前端组件复用性\n\n### 下一步发展\n\n**短期目标**\n- 完善用户认证和权限系统\n- 优化引用检测算法准确性\n- 增强前端用户体验\n\n**长期规划**\n- 支持多语言和国际化\n- 实现移动端应用\n- 添加机器学习模型优化\n- 构建开发者API平台\n\nSources:\n- [main.py](backend/app/main.py)\n- [config.py](backend/app/config.py)\n- [database.py](backend/app/database.py)\n- [layout.tsx](frontend/app/layout.tsx)\n- [providers.tsx](frontend/components/providers.tsx)\n- [scheduler.py](backend/app/workers/scheduler.py)\n- [citation_engine.py](backend/app/workers/citation_engine.py)\n- [auth.py](backend/app/api/auth.py)\n- [docker-compose.yml](docker-compose.yml)\n- [requirements.txt](backend/requirements.txt)\n- [package.json](frontend/package.json)\n\n\u003c/blog\u003e","gmt_create":"2026-04-22T18:54:45.079999+08:00","gmt_modified":"2026-04-22T18:54:45.079999+08:00","id":"1e2d007d-9249-436e-8822-c9b1a31580d1","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1"},"wiki_readme":{"content":"No readme file","gmt_create":"2026-04-22T18:53:55.057287+08:00","gmt_modified":"2026-04-22T18:53:55.057287+08:00","id":"354aa9f0-35fb-44a7-98d6-034981f130e6","repo_id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1"},"wiki_repo":{"id":"1095f823-f6f5-4e66-9aad-9f0b5b6b99d1","name":"GEO","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── .npm-cache/\\n│ ├── _cacache/\\n│ ├── _logs/\\n│ └── _npx/\\n├── .pytest_cache/\\n├── backend/\\n│ ├── alembic/\\n│ │ ├── __pycache__/\\n│ │ ├── versions/\\n│ │ │ ├── __pycache__/\\n│ │ │ └── 488d0bd5ab01_initial_migration.py\\n│ │ ├── README\\n│ │ ├── env.py\\n│ │ └── script.py.mako\\n│ ├── app/\\n│ │ ├── __pycache__/\\n│ │ ├── api/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── __init__.py\\n│ │ │ ├── auth.py\\n│ │ │ ├── citations.py\\n│ │ │ ├── deps.py\\n│ │ │ ├── queries.py\\n│ │ │ └── reports.py\\n│ │ ├── models/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── __init__.py\\n│ │ │ ├── citation_record.py\\n│ │ │ ├── query.py\\n│ │ │ ├── query_task.py\\n│ │ │ ├── subscription.py\\n│ │ │ └── user.py\\n│ │ ├── schemas/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── auth.py\\n│ │ │ ├── citation.py\\n│ │ │ └── query.py\\n│ │ ├── services/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── auth.py\\n│ │ │ ├── citation.py\\n│ │ │ └── query.py\\n│ │ ├── utils/\\n│ │ ├── workers/\\n│ │ │ ├── __pycache__/\\n│ │ │ ├── platforms/\\n│ │ │ │ ├── __pycache__/\\n│ │ │ │ ├── base.py\\n│ │ │ │ ├── kimi.py\\n│ │ │ │ └── wenxin.py\\n│ │ │ ├── __init__.py\\n│ │ │ ├── citation_engine.py\\n│ │ │ └── scheduler.py\\n│ │ ├── config.py\\n│ │ ├── database.py\\n│ │ └── main.py\\n│ ├── venv/\\n│ ├── Dockerfile\\n│ ├── alembic.ini\\n│ └── requirements.txt\\n├── docs/\\n├── frontend/\\n│ ├── .next/\\n│ ├── app/\\n│ │ ├── (auth)/\\n│ │ │ ├── login/\\n│ │ │ │ └── page.tsx\\n│ │ │ ├── register/\\n│ │ │ │ └── page.tsx\\n│ │ │ └── layout.tsx\\n│ │ ├── (dashboard)/\\n│ │ │ ├── dashboard/\\n│ │ │ │ ├── citations/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── queries/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── reports/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ ├── settings/\\n│ │ │ │ │ └── page.tsx\\n│ │ │ │ └── page.tsx\\n│ │ │ └── layout.tsx\\n│ │ ├── api/auth/[...nextauth]/\\n│ │ │ └── route.ts\\n│ │ ├── fonts/\\n│ │ ├── globals.css\\n│ │ ├── layout.tsx\\n│ │ └── page.tsx\\n│ ├── components/\\n│ │ ├── charts/\\n│ │ │ ├── platform-chart.tsx\\n│ │ │ └── trend-chart.tsx\\n│ │ ├── layout/\\n│ │ │ ├── header.tsx\\n│ │ │ └── sidebar.tsx\\n│ │ ├── ui/\\n│ │ │ ├── badge.tsx\\n│ │ │ ├── button.tsx\\n│ │ │ ├── card.tsx\\n│ │ │ ├── dialog.tsx\\n│ │ │ ├── dropdown-menu.tsx\\n│ │ │ ├── input.tsx\\n│ │ │ ├── label.tsx\\n│ │ │ ├── select.tsx\\n│ │ │ ├── table.tsx\\n│ │ │ └── tabs.tsx\\n│ │ └── providers.tsx\\n│ ├── lib/\\n│ │ ├── api.ts\\n│ │ ├── auth.ts\\n│ │ ├── platforms.ts\\n│ │ └── utils.ts\\n│ ├── node_modules/\\n│ ├── types/\\n│ │ └── next-auth.d.ts\\n│ ├── .eslintrc.json\\n│ ├── .gitignore\\n│ ├── Dockerfile\\n│ ├── README.md\\n│ ├── next-env.d.ts\\n│ ├── next.config.mjs\\n│ ├── package-lock.json\\n│ ├── package.json\\n│ ├── postcss.config.mjs\\n│ ├── tailwind.config.ts\\n│ ├── tsconfig.json\\n│ └── tsconfig.tsbuildinfo\\n├── tests/\\n│ ├── __pycache__/\\n│ ├── conftest.py\\n│ ├── test_auth.py\\n│ ├── test_citation_engine.py\\n│ ├── test_citations.py\\n│ └── test_queries.py\\n└── docker-compose.yml\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted: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","recovery_checkpoint":"wiki_generation_completed","last_commit_id":"eac12093d659483090ae8b5602372f10e15018fb","last_commit_update":"2026-05-23T15:26:11.57753+08:00","gmt_create":"2026-04-22T17:58:32.591608+08:00","gmt_modified":"2026-05-23T15:26:11.57753+08:00","extend_info":"{\"language\":\"zh\",\"active\":true,\"branch\":\"main\",\"shareStatus\":\"\",\"server_error_code\":\"\",\"cosy_version\":\"\"}"}} \ No newline at end of file diff --git a/README.md b/README.md index cd6b414..3aaca6d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # GEO - AI搜索引擎品牌曝光度优化平台 +[![CI Pipeline](https://github.com/YOUR_USERNAME/GEO/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_USERNAME/GEO/actions/workflows/ci.yml) +[![PR Check](https://github.com/YOUR_USERNAME/GEO/actions/workflows/pr-check.yml/badge.svg)](https://github.com/YOUR_USERNAME/GEO/actions/workflows/pr-check.yml) + ## 项目简介 GEO(Generative Engine Optimization)是一个SaaS平台,帮助品牌监测其在各大AI搜索引擎中的曝光度和引用情况。支持文心一言、Kimi、通义千问、豆包、讯飞星火、天工、清言等主流国内AI平台,以及通用搜索引擎。 diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..17d5ae3 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,13 @@ +venv/ +__pycache__/ +*.pyc +*.pyo +.pytest_cache/ +.env +.env.* +*.log +tests/ +alembic/versions/__pycache__/ +.git/ +.gitignore +README.md diff --git a/backend/Dockerfile b/backend/Dockerfile index c8e2af5..3c04f46 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -37,4 +37,9 @@ COPY . . EXPOSE 8000 -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ + CMD curl -f http://localhost:8000/api/health || exit 1 + +CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", \ + "--bind", "0.0.0.0:8000", "--timeout", "120", "--access-logfile", "-"] diff --git a/backend/alembic/versions/d4e6f8a0bc13_add_sentiment_fields.py b/backend/alembic/versions/059724556401_add_missing_sentiment_fields.py similarity index 75% rename from backend/alembic/versions/d4e6f8a0bc13_add_sentiment_fields.py rename to backend/alembic/versions/059724556401_add_missing_sentiment_fields.py index 92f24d6..ea0f334 100644 --- a/backend/alembic/versions/d4e6f8a0bc13_add_sentiment_fields.py +++ b/backend/alembic/versions/059724556401_add_missing_sentiment_fields.py @@ -1,8 +1,8 @@ -"""Add sentiment analysis fields to citation_records +"""add_missing_sentiment_fields -Revision ID: d4e6f8a0bc13 -Revises: c3d5e7f9ab12 -Create Date: 2026-05-19 10:00:00.000000 +Revision ID: 059724556401 +Revises: a7b9c1d3ef67 +Create Date: 2026-05-23 17:19:50.789398 """ from typing import Sequence, Union @@ -12,14 +12,15 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision: str = 'd4e6f8a0bc13' -down_revision: Union[str, Sequence[str], None] = 'c3d5e7f9ab12' +revision: str = '059724556401' +down_revision: Union[str, Sequence[str], None] = 'a7b9c1d3ef67' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: - # 添加情感分析字段 + """Upgrade schema.""" + # 添加情感分析字段到 citation_records 表 op.add_column('citation_records', sa.Column('sentiment', sa.String(20), nullable=True, comment='情感倾向: positive / neutral / negative') @@ -35,6 +36,7 @@ def upgrade() -> None: def downgrade() -> None: + """Downgrade schema.""" op.drop_column('citation_records', 'sentiment_key_phrases') op.drop_column('citation_records', 'sentiment_confidence') op.drop_column('citation_records', 'sentiment') diff --git a/backend/alembic/versions/d4e6f8a0bc23_add_citation_source_analysis_fields.py b/backend/alembic/versions/8ccb553ff975_add_citation_source_analysis_fields.py similarity index 81% rename from backend/alembic/versions/d4e6f8a0bc23_add_citation_source_analysis_fields.py rename to backend/alembic/versions/8ccb553ff975_add_citation_source_analysis_fields.py index 4e09274..12a3255 100644 --- a/backend/alembic/versions/d4e6f8a0bc23_add_citation_source_analysis_fields.py +++ b/backend/alembic/versions/8ccb553ff975_add_citation_source_analysis_fields.py @@ -1,8 +1,8 @@ -"""Add citation source analysis fields to citation_records +"""add_citation_source_analysis_fields -Revision ID: d4e6f8a0bc23 -Revises: c3d5e7f9ab12 -Create Date: 2026-05-19 10:00:00.000000 +Revision ID: 8ccb553ff975 +Revises: 059724556401 +Create Date: 2026-05-23 17:23:03.183460 """ from typing import Sequence, Union @@ -12,14 +12,14 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision: str = 'd4e6f8a0bc23' -down_revision: Union[str, Sequence[str], None] = 'c3d5e7f9ab12' +revision: str = '8ccb553ff975' +down_revision: Union[str, Sequence[str], None] = '059724556401' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: - """Add citation source analysis fields to citation_records table.""" + """Upgrade schema.""" # 数据来源类型标记 op.add_column( 'citation_records', @@ -53,7 +53,7 @@ def upgrade() -> None: def downgrade() -> None: - """Remove citation source analysis fields from citation_records table.""" + """Downgrade schema.""" op.drop_column('citation_records', 'ai_response_text') op.drop_column('citation_records', 'citation_contexts') op.drop_column('citation_records', 'source_titles') diff --git a/backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py b/backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py index 35e1860..d8f075c 100644 --- a/backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py +++ b/backend/alembic/versions/e5f7a9b1cd34_add_alerts_and_alert_settings_tables.py @@ -1,7 +1,7 @@ """Add alerts and alert_settings tables Revision ID: e5f7a9b1cd34 -Revises: d4e6f8a0bc23 +Revises: 8ccb553ff975 Create Date: 2026-05-20 10:00:00.000000 """ @@ -13,7 +13,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = 'e5f7a9b1cd34' -down_revision: Union[str, Sequence[str], None] = 'd4e6f8a0bc23' +down_revision: Union[str, Sequence[str], None] = '8ccb553ff975' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None diff --git a/backend/alembic/versions/e5f7a9b1cd34_add_suggestions_table.py b/backend/alembic/versions/e5f7a9b1cd35_add_suggestions_table.py similarity index 95% rename from backend/alembic/versions/e5f7a9b1cd34_add_suggestions_table.py rename to backend/alembic/versions/e5f7a9b1cd35_add_suggestions_table.py index 2b96e58..81c67c3 100644 --- a/backend/alembic/versions/e5f7a9b1cd34_add_suggestions_table.py +++ b/backend/alembic/versions/e5f7a9b1cd35_add_suggestions_table.py @@ -1,7 +1,7 @@ """add suggestions table -Revision ID: e5f7a9b1cd34 -Revises: d4e6f8a0bc23 +Revision ID: e5f7a9b1cd35 +Revises: e5f7a9b1cd34 Create Date: 2025-01-20 10:00:00.000000 """ from alembic import op @@ -9,8 +9,8 @@ import sqlalchemy as sa from sqlalchemy.dialects.postgresql import UUID, JSONB # revision identifiers -revision = "e5f7a9b1cd34" -down_revision = "d4e6f8a0bc23" +revision = "e5f7a9b1cd35" +down_revision = "e5f7a9b1cd34" branch_labels = None depends_on = None diff --git a/backend/app/agent_framework/base.py b/backend/app/agent_framework/base.py index 7cd7871..93a07cf 100644 --- a/backend/app/agent_framework/base.py +++ b/backend/app/agent_framework/base.py @@ -34,6 +34,7 @@ class BaseAgent(ABC): self._running_tasks: set[str] = set() self._listen_task: asyncio.Task | None = None self._heartbeat_task: asyncio.Task | None = None + self._semaphore: asyncio.Semaphore | None = None @property def status(self) -> AgentStatus: @@ -69,6 +70,14 @@ class BaseAgent(ABC): # 更新状态 self._status = AgentStatus.ONLINE + # 根据 capabilities 的 max_concurrency 初始化 Semaphore + capability = self.get_capabilities() + max_concurrency = getattr(capability, 'max_concurrency', 1) or 1 + self._semaphore = asyncio.Semaphore(max_concurrency) + logger.info( + f"Agent '{self.name}' concurrency limit set to {max_concurrency}" + ) + # 启动心跳 self._heartbeat_task = asyncio.create_task(self._heartbeat_loop()) @@ -172,7 +181,7 @@ class BaseAgent(ABC): try: task_data = json.loads(task_json) task = TaskMessage.from_dict(task_data) - asyncio.create_task(self._execute_task(task)) + asyncio.create_task(self._execute_task_with_semaphore(task)) except Exception as e: logger.error(f"Failed to parse task message: {e}") except asyncio.CancelledError: @@ -180,6 +189,14 @@ class BaseAgent(ABC): except Exception as e: logger.error(f"Task listener error for agent '{self.name}': {e}") + async def _execute_task_with_semaphore(self, task: TaskMessage): + """通过 Semaphore 限制并发执行任务""" + if self._semaphore is None: + await self._execute_task(task) + return + async with self._semaphore: + await self._execute_task(task) + async def _execute_task(self, task: TaskMessage): """执行单个任务""" self._running_tasks.add(task.task_id) diff --git a/backend/app/agent_framework/pipeline/engine.py b/backend/app/agent_framework/pipeline/engine.py index c3f676f..105854c 100644 --- a/backend/app/agent_framework/pipeline/engine.py +++ b/backend/app/agent_framework/pipeline/engine.py @@ -332,9 +332,10 @@ class PipelineEngine: resolved_inputs: dict[str, Any], ) -> StageResult: """ - Dry-run模式执行:模拟Agent返回结果。 + Dry-run模式执行:模拟Agent返回结果。仅用于测试/开发环境。 在没有dispatcher的环境下使用,用于测试和调试Pipeline定义。 + 如果在生产环境中触发,则记录 ERROR 级别告警。 Args: stage: 阶段定义 @@ -343,6 +344,15 @@ class PipelineEngine: Returns: 模拟的StageResult """ + import os + if os.environ.get("ENV", "development") == "production": + logger.error( + f"Pipeline 进入 dry-run 模式(stage={stage.name})!" + "生产环境中 TaskDispatcher 未正确初始化,请检查系统配置。" + ) + else: + logger.warning(f"[DRY-RUN] stage={stage.name} 返回模拟输出") + # 为声明的输出变量生成模拟值 mock_outputs: dict[str, Any] = {} for output_name in stage.outputs: diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index 86e08a2..f30fb2d 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -3,6 +3,7 @@ import uuid from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.ext.asyncio import AsyncSession +from app.api.base import PaginationParams from app.api.deps import get_current_user from app.database import get_db from app.models.user import User @@ -36,13 +37,12 @@ async def read_system_stats( @router.get("/users") async def read_users( - skip: int = Query(0, ge=0), - limit: int = Query(20, ge=1, le=100), + pagination: PaginationParams = Depends(PaginationParams), search: str | None = Query(None), db: AsyncSession = Depends(get_db), admin_user: User = Depends(get_admin_user), ): - return await get_users(db, skip=skip, limit=limit, search=search) + return await get_users(db, skip=pagination.offset, limit=pagination.limit, search=search) @router.get("/users/{user_id}") diff --git a/backend/app/api/agents.py b/backend/app/api/agents.py index 106a309..2f6ea05 100644 --- a/backend/app/api/agents.py +++ b/backend/app/api/agents.py @@ -25,6 +25,7 @@ from app.database import get_db from app.models.agent import AgentTask as AgentTaskModel from app.models.agent import AgentTaskLog as AgentTaskLogModel from app.models.user import User +from app.schemas.common import ErrorCode, ErrorResponse router = APIRouter() @@ -144,7 +145,7 @@ async def list_tasks( db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): - stmt = select(AgentTaskModel) + stmt = select(AgentTaskModel).where(AgentTaskModel.created_by == current_user.id) if task_status: stmt = stmt.where(AgentTaskModel.status == task_status) @@ -202,9 +203,11 @@ async def create_task( dispatcher = TaskDispatcher(settings.REDIS_URL) try: + # 从 current_user 获取 organization_id,优先使用用户的组织ID + org_id = str(current_user.organization_id) if current_user.organization_id else str(current_user.id) await dispatcher.dispatch( task=task, - organization_id=str(current_user.id), # fallback, 实际应从 user.org 取 + organization_id=org_id, created_by=str(current_user.id), ) return TaskCreateResponse( @@ -224,8 +227,35 @@ async def create_task( @router.get("/tasks/{task_id}", summary="获取任务状态") async def get_task_status( task_id: str, + db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): + # 权限校验:验证任务归属当前用户 + try: + task_uuid = uuid.UUID(task_id) + except ValueError: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid task_id format", + ) + + stmt = select(AgentTaskModel).where(AgentTaskModel.id == task_uuid) + result = await db.execute(stmt) + task = result.scalar_one_or_none() + if task is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Task '{task_id}' not found", + ) + if task.created_by != current_user.id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ErrorResponse( + detail="无权访问此任务", + code=ErrorCode.FORBIDDEN, + ).dict(), + ) + dispatcher = TaskDispatcher(settings.REDIS_URL) try: task_status_data = await dispatcher.get_task_status(task_id) @@ -242,8 +272,35 @@ async def get_task_status( @router.post("/tasks/{task_id}/cancel", summary="取消任务") async def cancel_task( task_id: str, + db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): + # 权限校验:验证任务归属当前用户 + try: + task_uuid = uuid.UUID(task_id) + except ValueError: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid task_id format", + ) + + stmt = select(AgentTaskModel).where(AgentTaskModel.id == task_uuid) + result = await db.execute(stmt) + task = result.scalar_one_or_none() + if task is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Task '{task_id}' not found", + ) + if task.created_by != current_user.id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ErrorResponse( + detail="无权取消此任务", + code=ErrorCode.FORBIDDEN, + ).dict(), + ) + dispatcher = TaskDispatcher(settings.REDIS_URL) try: await dispatcher.cancel_task(task_id) @@ -273,6 +330,24 @@ async def get_task_logs( detail="Invalid task_id format", ) + # 权限校验:验证任务归属当前用户 + task_stmt = select(AgentTaskModel).where(AgentTaskModel.id == task_uuid) + task_result = await db.execute(task_stmt) + task = task_result.scalar_one_or_none() + if task is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Task '{task_id}' not found", + ) + if task.created_by != current_user.id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ErrorResponse( + detail="无权访问此任务日志", + code=ErrorCode.FORBIDDEN, + ).dict(), + ) + stmt = ( select(AgentTaskLogModel) .where(AgentTaskLogModel.task_id == task_uuid) diff --git a/backend/app/api/analytics.py b/backend/app/api/analytics.py index 545b980..bd1e5ca 100644 --- a/backend/app/api/analytics.py +++ b/backend/app/api/analytics.py @@ -30,13 +30,10 @@ router = APIRouter() # 辅助:获取当前用户所属组织ID # ------------------------------------------------------------------ # -async def _get_org_id(current_user: User = Depends(get_current_user)) -> str: +async def _get_org_id(current_user: User = Depends(get_current_user)) -> str | None: org_id = getattr(current_user, "organization_id", None) if not org_id: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="用户未关联组织", - ) + return None return str(org_id) @@ -52,9 +49,14 @@ async def _get_org_id(current_user: User = Depends(get_current_user)) -> str: ) async def record_publish( body: PublishRecordCreate, - org_id: str = Depends(_get_org_id), + org_id: str | None = Depends(_get_org_id), db: AsyncSession = Depends(get_db), ): + if not org_id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="用户未关联组织,无法记录发布", + ) tracker = AnalyticsTracker(db) record = await tracker.record_publish(org_id, body.model_dump()) return record @@ -104,9 +106,18 @@ async def update_metrics( summary="获取全局效果概览", ) async def get_overview( - org_id: str = Depends(_get_org_id), + org_id: str | None = Depends(_get_org_id), db: AsyncSession = Depends(get_db), ): + if not org_id: + return OverviewStatsResponse( + total_published=0, + total_views=0, + total_interactions=0, + total_ai_citations=0, + avg_engagement_rate=0.0, + platform_distribution={}, + ) tracker = AnalyticsTracker(db) overview = await tracker.get_overview(org_id) return overview @@ -157,9 +168,11 @@ async def get_content_performance( async def get_top_performing( sort_by: str = Query(default="views", description="排序字段: views/likes/comments/shares/ai_citation_count/read_completion_rate"), limit: int = Query(default=10, ge=1, le=50), - org_id: str = Depends(_get_org_id), + org_id: str | None = Depends(_get_org_id), db: AsyncSession = Depends(get_db), ): + if not org_id: + return TopContentResponse(items=[], sort_by=sort_by, total=0) tracker = AnalyticsTracker(db) items = await tracker.get_top_performing(org_id, limit=limit, sort_by=sort_by) return TopContentResponse(items=items, sort_by=sort_by, total=len(items)) @@ -177,9 +190,11 @@ async def get_top_performing( async def list_insights( limit: int = Query(default=20, ge=1, le=100), insight_type: Optional[str] = Query(default=None), - org_id: str = Depends(_get_org_id), + org_id: str | None = Depends(_get_org_id), db: AsyncSession = Depends(get_db), ): + if not org_id: + return [] stmt = ( select(OptimizationInsight) .where(OptimizationInsight.organization_id == org_id) @@ -204,9 +219,11 @@ async def list_insights( summary="触发AI生成洞察建议", ) async def generate_insights( - org_id: str = Depends(_get_org_id), + org_id: str | None = Depends(_get_org_id), db: AsyncSession = Depends(get_db), ): + if not org_id: + return [] generator = InsightGenerator() insights = await generator.generate_insights(org_id, db) return insights diff --git a/backend/app/api/auth.py b/backend/app/api/auth.py index d7691d2..2e22dbf 100644 --- a/backend/app/api/auth.py +++ b/backend/app/api/auth.py @@ -5,8 +5,10 @@ from app.api.deps import get_current_user from app.database import get_db from app.models.user import User from app.schemas.auth import ( + AccessTokenResponse, ChangePasswordRequest, ForgotPasswordRequest, + RefreshTokenRequest, ResetPasswordRequest, TokenResponse, UpdateProfileRequest, @@ -19,13 +21,16 @@ from app.services.auth import ( authenticate_user, change_password as change_password_service, create_access_token, + create_refresh_token, register_user, reset_password as reset_password_service, send_reset_link, send_verification_code, update_profile as update_profile_service, verify_email as verify_email_service, + verify_refresh_token, ) +from app.services.cache import get_cache_service, TTL_USER_PROFILE router = APIRouter() @@ -34,8 +39,9 @@ router = APIRouter() async def register(user_data: UserRegister, db: AsyncSession = Depends(get_db)): try: user = await register_user(db, user_data) - except ValueError as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) if str(e) else "邮箱已被注册") + except ValueError: + # 不泄露具体原因,防止用户枚举 + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="注册失败,请检查输入信息是否已被使用") return user @@ -43,6 +49,7 @@ async def register(user_data: UserRegister, db: AsyncSession = Depends(get_db)): async def login(user_data: UserLogin, db: AsyncSession = Depends(get_db)): user = await authenticate_user(db, user_data.email, user_data.password) if not user: + # 统一错误消息,防止用户枚举(不区分“用户不存在” vs “密码错误”) raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="邮箱或密码错误", @@ -50,15 +57,58 @@ async def login(user_data: UserLogin, db: AsyncSession = Depends(get_db)): ) access_token = create_access_token(data={"sub": str(user.id)}) + refresh_token = create_refresh_token(data={"sub": str(user.id)}) return { "access_token": access_token, "token_type": "bearer", + "refresh_token": refresh_token, "user": user, } +@router.post("/refresh", response_model=AccessTokenResponse) +async def refresh_token(req: RefreshTokenRequest): + """ + 刷新接口:使用 refresh_token 获取新的 access_token + refresh_token(滑动过期) + """ + try: + payload = verify_refresh_token(req.refresh_token) + except ValueError: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="刷新令牌无效或已过期", + headers={"WWW-Authenticate": "Bearer"}, + ) + + user_id = payload.get("sub") + if not user_id: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="刷新令牌无效或已过期", + headers={"WWW-Authenticate": "Bearer"}, + ) + + new_access_token = create_access_token(data={"sub": user_id}) + new_refresh_token = create_refresh_token(data={"sub": user_id}) # 滑动过期 + return { + "access_token": new_access_token, + "token_type": "bearer", + "refresh_token": new_refresh_token, + } + + @router.get("/me", response_model=UserResponse) -async def read_current_user(current_user: User = Depends(get_current_user)): +async def read_current_user( + current_user: User = Depends(get_current_user), +): + cache = get_cache_service() + cache_key = f"user:profile:{current_user.id}" + cached = await cache.get_json(cache_key) + if cached is not None: + return cached + + user_data = UserResponse.model_validate(current_user).model_dump(mode="json") + await cache.set_json(cache_key, user_data, expire=TTL_USER_PROFILE) return current_user @@ -111,4 +161,9 @@ async def update_profile( updated_user = await update_profile_service(db, user.id, req) if not updated_user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + # 失效用户配置缓存 + cache = get_cache_service() + await cache.delete(f"user:profile:{user.id}") + return updated_user diff --git a/backend/app/api/base.py b/backend/app/api/base.py new file mode 100644 index 0000000..409ce0b --- /dev/null +++ b/backend/app/api/base.py @@ -0,0 +1,46 @@ +"""通用分页与过滤工具,供各 API 路由复用。""" +from typing import Generic, TypeVar + +from fastapi import Query +from pydantic import BaseModel, computed_field + +T = TypeVar("T") + + +class PaginationParams: + """依赖注入式分页参数(可直接用于 Depends)。""" + + def __init__( + self, + page: int = Query(1, ge=1, description="页码,从 1 开始"), + page_size: int = Query(20, ge=1, le=100, description="每页条数"), + ): + self.page = page + self.page_size = page_size + + @property + def offset(self) -> int: + return (self.page - 1) * self.page_size + + @property + def limit(self) -> int: + return self.page_size + + +class PaginatedResponse(BaseModel, Generic[T]): + """通用分页响应结构。""" + + items: list[T] + total: int + page: int + page_size: int + + @computed_field # type: ignore[misc] + @property + def total_pages(self) -> int: + if self.page_size == 0: + return 0 + import math + return math.ceil(self.total / self.page_size) + + model_config = {"from_attributes": True} diff --git a/backend/app/api/brands.py b/backend/app/api/brands.py index e5f485f..fa704c0 100644 --- a/backend/app/api/brands.py +++ b/backend/app/api/brands.py @@ -1,10 +1,12 @@ """Brands API endpoints.""" +import json import uuid from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import selectinload from app.api.deps import get_current_user from app.api.competitors import router as competitors_router @@ -13,6 +15,7 @@ from app.database import get_db from app.models.user import User from app.models.brand import Brand from app.schemas.brand import BrandCreate, BrandUpdate, BrandResponse, BrandListResponse +from app.services.cache import get_cache_service, TTL_BRANDS router = APIRouter() @@ -29,15 +32,32 @@ async def get_brands( db: AsyncSession = Depends(get_db), ): """Get all brands for the current user.""" - stmt = select(Brand, func.count().over().label("total")).where( - Brand.user_id == current_user.id + cache = get_cache_service() + cache_key = f"brands:{current_user.id}" + + # 先读缓存 + cached = await cache.get_json(cache_key) + if cached is not None: + return cached + + # 修复 N+1:一次性加载 competitors 和 suggestions + stmt = ( + select(Brand) + .where(Brand.user_id == current_user.id) + .options( + selectinload(Brand.competitors), + selectinload(Brand.suggestions), + ) ) result = await db.execute(stmt) - rows = result.all() - - items = [row[0] for row in rows] + items = list(result.scalars().all()) total = len(items) + response_data = {"items": [BrandResponse.model_validate(b).model_dump(mode="json") for b in items], "total": total} + + # 写入缓存(TTL: 5 分钟) + await cache.set_json(cache_key, response_data, expire=TTL_BRANDS) + return {"items": items, "total": total} @@ -60,6 +80,11 @@ async def create_brand( db.add(brand) await db.commit() await db.refresh(brand) + + # 失效该用户的品牌列表缓存 + cache = get_cache_service() + await cache.delete(f"brands:{current_user.id}") + return brand @@ -107,6 +132,11 @@ async def update_brand( await db.commit() await db.refresh(brand) + + # 失效该用户的品牌列表缓存 + cache = get_cache_service() + await cache.delete(f"brands:{current_user.id}") + return brand @@ -129,4 +159,9 @@ async def delete_brand( await db.delete(brand) await db.commit() + + # 失效该用户的品牌列表缓存 + cache = get_cache_service() + await cache.delete(f"brands:{current_user.id}") + return None \ No newline at end of file diff --git a/backend/app/api/content.py b/backend/app/api/content.py index cb4c89e..4011f1b 100644 --- a/backend/app/api/content.py +++ b/backend/app/api/content.py @@ -1,5 +1,6 @@ """内容生产API - 串联Agent Pipeline""" import json +import logging import re from typing import Optional @@ -13,6 +14,8 @@ from app.database import get_db from app.models.content import Content, ContentVersion from app.models.user import User +logger = logging.getLogger(__name__) + router = APIRouter() @@ -38,6 +41,44 @@ class ContentGenerateResponse(BaseModel): pipeline_stages: list[dict] = [] # 每个阶段的执行结果摘要 +async def _get_knowledge_context( + db: AsyncSession, + brand_name: str, + knowledge_base_ids: list[str], + target_keyword: str, +) -> str: + """ + 从知识库检索与查询相关的上下文。 + + 如果有知识库ID,则调用 RAGService.search 获取相关内容; + 否则返回空字符串,不影响后续流程。 + """ + if not knowledge_base_ids: + return "" + + try: + from app.services.knowledge.rag_service import RAGService + rag_service = RAGService() + results = await rag_service.search( + session=db, + query=f"{brand_name} {target_keyword}" if brand_name else target_keyword, + knowledge_base_ids=knowledge_base_ids, + top_k=3, + ) + if results: + context_parts = [] + for r in results: + content = r.get("content", "") + title = r.get("document_title", "") + if content: + context_parts.append(f"[{title}] {content}") + return "\n".join(context_parts) + return "" + except Exception as e: + logger.warning(f"知识库检索失败,将不使用知识库上下文: {e}") + return "" + + @router.post("/generate", response_model=ContentGenerateResponse) async def generate_content( req: ContentGenerateRequest, @@ -65,6 +106,11 @@ async def generate_content( try: provider = LLMFactory.get_default() + # 获取知识库上下文 + knowledge_context = await _get_knowledge_context( + db, req.brand_name, req.knowledge_base_ids, req.target_keyword + ) + # Stage 1: 内容生成 gen_variables = { "topic_title": req.target_keyword, @@ -74,7 +120,7 @@ async def generate_content( "content_style": req.content_style, "word_count": str(req.word_count), "brand_name": req.brand_name, - "knowledge_context": "暂无", # TODO: 对接RAG检索 + "knowledge_context": knowledge_context, } messages = CONTENT_GENERATOR_TEMPLATE.render(gen_variables) response = await provider.chat(messages, temperature=0.7, max_tokens=req.word_count * 2) @@ -191,4 +237,4 @@ async def generate_topics( return {"status": "success", "topics": topics} except LLMError as e: - raise HTTPException(status_code=502, detail=str(e)) + raise HTTPException(status_code=502, detail=str(e)) \ No newline at end of file diff --git a/backend/app/api/dashboard.py b/backend/app/api/dashboard.py index 3efed40..70760c9 100644 --- a/backend/app/api/dashboard.py +++ b/backend/app/api/dashboard.py @@ -22,6 +22,7 @@ from app.schemas.dashboard import ( from app.services.scoring_service import ScoringService, get_health_level from app.services.sentiment_service import get_sentiment_service from app.schemas.scoring import CitationResult +from app.services.cache import get_cache_service, TTL_DASHBOARD router = APIRouter() @@ -355,7 +356,8 @@ async def get_dashboard_stats( - 竞品地位(领先/落后数量) - 最近查询记录 """ - # Get the first brand if not specified + cache = get_cache_service() + # 如果 brand_id 尚未确定,先查库取第一个品牌 if brand_id is None: brand_stmt = select(Brand).where(Brand.user_id == current_user.id).limit(1) brand_result = await db.execute(brand_stmt) @@ -377,6 +379,12 @@ async def get_dashboard_stats( total_platforms=7, ) + # 尝试从缓存读取(TTL: 2 分钟) + cache_key = f"dashboard:stats:{current_user.id}:{brand_id}" + cached = await cache.get_json(cache_key) + if cached is not None: + return cached + # Get brand name brand_stmt = select(Brand).where(Brand.id == brand_id) brand_result = await db.execute(brand_stmt) @@ -455,7 +463,7 @@ async def get_dashboard_stats( # Health level health_level = get_health_level(overall_score) - return DashboardStatsResponse( + response = DashboardStatsResponse( overall_score=round(overall_score, 2), health_level=health_level, score_change=score_change, @@ -468,3 +476,12 @@ async def get_dashboard_stats( total_platforms=7, brand_name=brand_name, ) + + # 将结果写入缓存(TTL: 2 分钟) + await cache.set_json( + cache_key, + response.model_dump(mode="json"), + expire=TTL_DASHBOARD, + ) + + return response diff --git a/backend/app/api/lifecycle.py b/backend/app/api/lifecycle.py index 85602fb..61e7cb7 100644 --- a/backend/app/api/lifecycle.py +++ b/backend/app/api/lifecycle.py @@ -31,6 +31,14 @@ STAGE_NAMES = { 5: "持续运维", } +STAGE_INT_TO_STR = { + 1: "diagnosis", + 2: "strategy", + 3: "content", + 4: "publishing", + 5: "monitoring", +} + # ---------- helpers ---------- @@ -82,6 +90,25 @@ async def _load_project_with_stages( # ---------- endpoints ---------- +@router.get("/projects/", response_model=list[ProjectResponse]) +async def list_projects( + db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_user), +): + org_id = current_user.organization_id + if not org_id: + return [] + stmt = ( + select(LifecycleProject) + .where(LifecycleProject.organization_id == org_id) + .options(selectinload(LifecycleProject.stages)) + .order_by(LifecycleProject.created_at.desc()) + ) + result = await db.execute(stmt) + projects = result.scalars().all() + return projects + + @router.get("/projects/stats", response_model=ProjectStatsResponse) async def project_stats( db: AsyncSession = Depends(get_db), @@ -92,6 +119,10 @@ async def project_stats( return ProjectStatsResponse( total_projects=0, active_projects=0, + completed_projects=0, + contents_produced=0, + avg_ai_citation_rate=None, + current_stage_distribution={}, stage_distribution={}, completion_rate=0.0, ) @@ -127,9 +158,70 @@ async def project_stats( done = comp_result.scalar() or 0 completion_rate = round(done / total, 4) if total > 0 else 0.0 + # completed projects + completed_stmt = select( + func.count().filter(LifecycleProject.status == "completed").label("completed"), + ).where(LifecycleProject.organization_id == org_id) + completed_result = await db.execute(completed_stmt) + completed = completed_result.scalar() or 0 + + # contents produced (count from content table if available) + try: + from app.models.content import Content + contents_stmt = select(func.count()).where(Content.organization_id == org_id) + contents_result = await db.execute(contents_stmt) + contents_produced = contents_result.scalar() or 0 + except Exception: + contents_produced = 0 + + # avg AI citation rate + try: + from app.models.citation_record import CitationRecord + from app.models.query import Query as QueryModel + # Query uses user_id, so join through users table to get org members + from app.models.organization import OrgMember + org_user_ids_stmt = select(OrgMember.user_id).where(OrgMember.organization_id == org_id) + org_user_ids_result = await db.execute(org_user_ids_stmt) + org_user_ids = [r.user_id for r in org_user_ids_result.all()] + if org_user_ids: + citation_stmt = select( + func.count().label("total_citations"), + func.count().filter(CitationRecord.cited == True).label("cited_count"), + ).join(QueryModel, CitationRecord.query_id == QueryModel.id).where( + QueryModel.user_id.in_(org_user_ids), + ) + citation_result = await db.execute(citation_stmt) + citation_row = citation_result.one() + total_citations = citation_row.total_citations or 0 + cited_count = citation_row.cited_count or 0 + avg_ai_citation_rate = round(cited_count / total_citations, 4) if total_citations > 0 else None + else: + avg_ai_citation_rate = None + except Exception: + avg_ai_citation_rate = None + + # current stage distribution (map int stage to string) + current_stage_dist_stmt = ( + select( + LifecycleProject.current_stage, + func.count().label("cnt"), + ) + .where(LifecycleProject.organization_id == org_id) + .group_by(LifecycleProject.current_stage) + ) + current_stage_dist_result = await db.execute(current_stage_dist_stmt) + current_stage_distribution = {} + for r in current_stage_dist_result.all(): + stage_key = STAGE_INT_TO_STR.get(r.current_stage, str(r.current_stage)) + current_stage_distribution[stage_key] = current_stage_distribution.get(stage_key, 0) + r.cnt + return ProjectStatsResponse( total_projects=total, active_projects=active, + completed_projects=completed, + contents_produced=contents_produced, + avg_ai_citation_rate=avg_ai_citation_rate, + current_stage_distribution=current_stage_distribution, stage_distribution=stage_distribution, completion_rate=completion_rate, ) @@ -143,7 +235,7 @@ async def project_timeline( ): org_id = current_user.organization_id if not org_id: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No organization found") + return [] project = await _load_project_with_stages(db, project_id, org_id) if not project: @@ -238,7 +330,7 @@ async def list_stages( ): org_id = current_user.organization_id if not org_id: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No organization found") + return [] project = await _load_project_with_stages(db, project_id, org_id) if not project: @@ -257,7 +349,7 @@ async def update_stage( ): org_id = current_user.organization_id if not org_id: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No organization found") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="用户未关联组织,无法修改项目阶段") # verify project ownership project = await _load_project_with_stages(db, project_id, org_id) diff --git a/backend/app/api/onboarding.py b/backend/app/api/onboarding.py new file mode 100644 index 0000000..471e9cf --- /dev/null +++ b/backend/app/api/onboarding.py @@ -0,0 +1,514 @@ +"""Onboarding API endpoints - 新用户引导流程""" +import logging +import uuid +from typing import Optional + +from fastapi import APIRouter, Depends, HTTPException, Query, status +from pydantic import BaseModel, Field +from sqlalchemy import select, func +from sqlalchemy.ext.asyncio import AsyncSession + +from app.api.deps import get_current_user +from app.api.competitors import ( + INDUSTRY_COMPETITORS, + _get_rule_based_recommendations, + _get_llm_recommendations, + CompetitorRecommendationItem, +) +from app.config import settings +from app.database import get_db +from app.models.user import User +from app.models.brand import Brand +from app.models.competitor import Competitor +from app.models.citation_record import CitationRecord +from app.models.query import Query as QueryModel +from app.services.scoring_service import ScoringService +from app.schemas.brand import BrandCreate, BrandResponse + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/onboarding", tags=["onboarding"]) + + +# ------------------------------------------------------------------ +# Request / Response schemas +# ------------------------------------------------------------------ + +class OnboardingBrandCreate(BaseModel): + """Onboarding 创建品牌请求(简化版)""" + name: str = Field(..., min_length=2, max_length=50, description="品牌名称") + description: Optional[str] = Field(None, max_length=500, description="品牌描述") + industry: Optional[str] = Field(None, max_length=50, description="行业") + + +class OnboardingStatusResponse(BaseModel): + """Onboarding 状态响应""" + completed: bool + brand_id: Optional[str] = None + current_step: int + + +class CompetitorRecommendationSimple(BaseModel): + """简化竞品推荐项""" + name: str + description: str + confidence: float + + +class CompetitorRecommendationSimpleResponse(BaseModel): + """简化竞品推荐响应""" + recommendations: list[CompetitorRecommendationSimple] + + +class HealthReportResponse(BaseModel): + """初始健康评分报告""" + brand_id: str + brand_name: str + overall_score: float + platform_scores: dict + strengths: list[str] + weaknesses: list[str] + competitor_scores: list[dict] + + +class ActionSuggestion(BaseModel): + """行动建议项""" + title: str + description: str + priority: str # high / medium / low + action_type: str # e.g. coverage, keyword, sentiment, platform + + +class ActionSuggestionsResponse(BaseModel): + """行动建议响应""" + suggestions: list[ActionSuggestion] + + +class OnboardingCompleteResponse(BaseModel): + """完成 onboarding 响应""" + success: bool + + +# ------------------------------------------------------------------ +# Endpoints +# ------------------------------------------------------------------ + +@router.get("/status", response_model=OnboardingStatusResponse) +async def get_onboarding_status( + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + 检查当前用户的 onboarding 状态。 + + 通过查询 brands 表判断:用户是否已创建品牌(即完成 onboarding)。 + - completed=True 且 brand_id 有值 → 已完成 + - completed=False, current_step=1 → 需要创建品牌 + """ + stmt = select(Brand).where(Brand.user_id == current_user.id) + result = await db.execute(stmt) + brand = result.scalar_one_or_none() + + if brand: + return OnboardingStatusResponse( + completed=True, + brand_id=str(brand.id), + current_step=4, + ) + + return OnboardingStatusResponse( + completed=False, + brand_id=None, + current_step=1, + ) + + +@router.post("/brand", response_model=BrandResponse, status_code=status.HTTP_201_CREATED) +async def create_onboarding_brand( + brand_data: OnboardingBrandCreate, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + Onboarding 流程中创建品牌。 + + 复用 Brand 模型,将简化字段映射到完整 BrandCreate。 + """ + full_brand_data = BrandCreate( + name=brand_data.name, + aliases=[], + website=None, + industry=brand_data.industry, + platforms=["wenxin", "kimi"], + frequency="weekly", + ) + + brand = Brand( + user_id=current_user.id, + name=full_brand_data.name, + aliases=full_brand_data.aliases, + website=full_brand_data.website, + industry=full_brand_data.industry, + platforms=full_brand_data.platforms, + frequency=full_brand_data.frequency, + ) + db.add(brand) + await db.commit() + await db.refresh(brand) + + return brand + + +@router.get("/competitor-recommendations", response_model=CompetitorRecommendationSimpleResponse) +async def get_onboarding_competitor_recommendations( + brand_id: uuid.UUID = Query(..., description="品牌ID"), + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + 根据品牌推荐竞品。 + + 复用 brands/competitors 中的推荐逻辑, + 支持 LLM 智能推荐和规则推荐两种模式。 + """ + # 验证品牌归属 + stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id) + result = await db.execute(stmt) + brand = result.scalar_one_or_none() + + if not brand: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="品牌不存在", + ) + + # 获取已有竞品名称(排除) + existing_stmt = select(Competitor.name).where(Competitor.brand_id == brand_id) + existing_result = await db.execute(existing_stmt) + existing_names = [row[0] for row in existing_result.all()] + + # 选择推荐策略 + if settings.ENABLE_LLM and settings.DEEPSEEK_API_KEY: + try: + rec_items = await _get_llm_recommendations( + brand_name=brand.name, + industry=brand.industry, + existing_names=existing_names, + ) + except Exception as e: + logger.warning(f"Onboarding LLM竞品推荐失败,回退规则推荐: {e}") + rec_items = _get_rule_based_recommendations( + brand_name=brand.name, + industry=brand.industry, + existing_names=existing_names, + ) + else: + rec_items = _get_rule_based_recommendations( + brand_name=brand.name, + industry=brand.industry, + existing_names=existing_names, + ) + + # 转换为简化格式 + recommendations = [] + for item in rec_items: + confidence = 0.8 if brand.industry and brand.industry in INDUSTRY_COMPETITORS else 0.5 + recommendations.append(CompetitorRecommendationSimple( + name=item.name, + description=item.reason, + confidence=confidence, + )) + + return CompetitorRecommendationSimpleResponse(recommendations=recommendations) + + +@router.get("/health-report/{brand_id}", response_model=HealthReportResponse) +async def get_onboarding_health_report( + brand_id: uuid.UUID, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + 获取品牌初始健康评分报告。 + + 基于 citation_records 表统计品牌的引用数据, + 如果没有引用数据则返回初始化状态(overall_score: 0)。 + """ + # 验证品牌归属 + stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id) + result = await db.execute(stmt) + brand = result.scalar_one_or_none() + + if not brand: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="品牌不存在", + ) + + # 查询与品牌关联的 queries + queries_stmt = select(QueryModel).where( + QueryModel.user_id == current_user.id, + QueryModel.target_brand == brand.name, + ) + queries_result = await db.execute(queries_stmt) + queries = list(queries_result.scalars().all()) + + # 没有查询数据 → 返回初始化状态 + if not queries: + return HealthReportResponse( + brand_id=str(brand.id), + brand_name=brand.name, + overall_score=0.0, + platform_scores={}, + strengths=["品牌已创建,等待数据采集"], + weaknesses=["尚无AI平台引用数据,需等待查询执行"], + competitor_scores=[], + ) + + query_ids = [q.id for q in queries] + + # 获取引用记录 + citations_stmt = select(CitationRecord).where( + CitationRecord.query_id.in_(query_ids), + ) + citations_result = await db.execute(citations_stmt) + citations = list(citations_result.scalars().all()) + + total = len(citations) + cited = [c for c in citations if c.cited] + + # 计算各平台评分 + platform_scores: dict[str, float] = {} + platforms_seen: dict[str, dict] = {} # {platform: {total, cited}} + + for c in citations: + p = c.platform or "unknown" + if p not in platforms_seen: + platforms_seen[p] = {"total": 0, "cited": 0} + platforms_seen[p]["total"] += 1 + if c.cited: + platforms_seen[p]["cited"] += 1 + + for p, data in platforms_seen.items(): + rate = (data["cited"] / data["total"] * 100) if data["total"] > 0 else 0.0 + platform_scores[p] = round(rate, 2) + + # 使用 ScoringService 计算 overall_score + scoring_service = ScoringService() + sentiment_counts = {"positive": 0, "neutral": 0, "negative": 0} + for c in cited: + sentiment = c.sentiment or "neutral" + if sentiment in sentiment_counts: + sentiment_counts[sentiment] += 1 + + from app.schemas.scoring import CitationResult + citation_results = [ + CitationResult( + cited=c.cited, + position=c.citation_position, + citation_text=c.citation_text, + sentiment=c.sentiment or "neutral", + confidence=c.confidence or 0.0, + ) + for c in cited + ] + positions = [c.citation_position for c in cited if c.cited] + + # 获取竞品信息 + competitor_stmt = select(Competitor).where(Competitor.brand_id == brand_id) + competitor_result = await db.execute(competitor_stmt) + competitors = list(competitor_result.scalars().all()) + competitor_names = [c.name for c in competitors] + competitor_mentions: dict[str, int] = {} + for comp_name in competitor_names: + count = sum( + 1 for c in citations + if c.cited and c.competitor_brands and comp_name in c.competitor_brands + ) + if count > 0: + competitor_mentions[comp_name] = count + + v2_result = scoring_service.calculate_v2( + mentioned_count=len(cited), + total_queries=total, + positions=positions, + sentiment_counts=sentiment_counts, + citations=citation_results, + brand_mentions=len(cited), + competitor_mentions=competitor_mentions, + ) + + # 生成 strengths/weaknesses + strengths = [] + weaknesses = [] + + if total == 0: + strengths.append("品牌已创建") + weaknesses.append("尚无引用数据") + else: + mention_rate = len(cited) / total * 100 if total > 0 else 0 + if mention_rate >= 50: + strengths.append(f"提及率较高 ({round(mention_rate, 1)}%)") + else: + weaknesses.append(f"提及率偏低 ({round(mention_rate, 1)}%)") + + for p, score in platform_scores.items(): + if score >= 60: + strengths.append(f"{p} 平台表现良好 ({score}%)") + elif score > 0: + weaknesses.append(f"{p} 平台覆盖率不足 ({score}%)") + + if sentiment_counts["positive"] > sentiment_counts["negative"]: + strengths.append("情感倾向正面") + elif sentiment_counts["negative"] > sentiment_counts["positive"]: + weaknesses.append("情感倾向偏负面") + + if not strengths: + strengths.append("已有初步引用数据") + if not weaknesses: + weaknesses.append("暂无明显短板") + + # 竞品评分 + competitor_scores = [] + for comp_name, mentions in competitor_mentions.items(): + comp_score = round(mentions / total * 100, 2) if total > 0 else 0.0 + competitor_scores.append({ + "name": comp_name, + "score": comp_score, + }) + + return HealthReportResponse( + brand_id=str(brand.id), + brand_name=brand.name, + overall_score=round(v2_result.overall_score, 2), + platform_scores=platform_scores, + strengths=strengths, + weaknesses=weaknesses, + competitor_scores=competitor_scores, + ) + + +@router.get("/action-suggestions/{brand_id}", response_model=ActionSuggestionsResponse) +async def get_onboarding_action_suggestions( + brand_id: uuid.UUID, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + 根据健康报告生成行动建议(基于规则引擎,不需要 LLM)。 + """ + # 先获取健康报告数据(复用逻辑) + report = await get_onboarding_health_report(brand_id, current_user, db) + + suggestions = [] + + # 规则引擎:基于评分和平台数据生成建议 + if report.overall_score < 20: + suggestions.append(ActionSuggestion( + title="提升 AI 平台覆盖率", + description=f"当前综合评分仅 {report.overall_score},品牌在AI搜索中几乎未被提及。建议增加查询词覆盖面,让AI平台更频繁地引用品牌。", + priority="high", + action_type="coverage", + )) + + if report.overall_score < 50: + suggestions.append(ActionSuggestion( + title="优化核心关键词", + description="品牌在关键查询词下的提及率偏低,建议调整查询关键词策略,聚焦行业核心术语。", + priority="high", + action_type="keyword", + )) + + # 平台维度建议 + for platform, score in report.platform_scores.items(): + if score < 30: + suggestions.append(ActionSuggestion( + title=f"提升 {platform} 平台覆盖率", + description=f"品牌在 {platform} 平台的引用率仅为 {score}%,需要针对性优化该平台的内容策略。", + priority="medium", + action_type="platform", + )) + + # 情感维度建议 + if "情感倾向偏负面" in report.weaknesses: + suggestions.append(ActionSuggestion( + title="改善品牌情感倾向", + description="AI平台对品牌的情感评价偏负面,建议发布正面品牌内容、优化品牌描述以改善情感得分。", + priority="medium", + action_type="sentiment", + )) + + # 竞品对比建议 + for comp in report.competitor_scores: + if comp["score"] > report.overall_score: + suggestions.append(ActionSuggestion( + title=f"应对竞品 {comp['name']} 威胁", + description=f"竞品 {comp['name']} 评分 ({comp['score']}) 高于本品牌 ({report.overall_score}),建议分析竞品优势领域并制定差异化策略。", + priority="high", + action_type="competitive", + )) + + # 如果没有引用数据,给出基础建议 + if report.overall_score == 0: + suggestions = [ + ActionSuggestion( + title="设置核心查询词", + description="品牌尚无查询数据,建议首先设置与品牌最相关的核心查询词,让系统开始数据采集。", + priority="high", + action_type="keyword", + ), + ActionSuggestion( + title="添加竞品对比", + description="添加主要竞品以便进行对比分析,了解品牌在市场中的定位。", + priority="medium", + action_type="coverage", + ), + ActionSuggestion( + title="完善品牌信息", + description="补充品牌别名、网站、行业等详细信息,有助于提升AI平台识别率。", + priority="medium", + action_type="brand_info", + ), + ] + + # 确保至少有1条建议 + if not suggestions: + suggestions.append(ActionSuggestion( + title="持续监测品牌表现", + description="品牌表现良好,建议持续监测并保持当前策略。", + priority="low", + action_type="monitor", + )) + + return ActionSuggestionsResponse(suggestions=suggestions) + + +@router.post("/complete/{brand_id}", response_model=OnboardingCompleteResponse) +async def complete_onboarding( + brand_id: uuid.UUID, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + """ + 标记用户已完成 onboarding。 + + 通过验证品牌存在并归属当前用户来确认完成状态。 + User 模型当前没有 onboarding_completed 专用字段, + 品牌的创建即代表 onboarding 完成。 + """ + # 验证品牌归属 + stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id) + result = await db.execute(stmt) + brand = result.scalar_one_or_none() + + if not brand: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="品牌不存在", + ) + + # 品牌已创建即代表 onboarding 完成,无需额外字段更新 + # 后续如需专用字段,可通过 alembic 迁移添加 user.onboarding_completed + logger.info(f"User {current_user.id} completed onboarding with brand {brand_id}") + + return OnboardingCompleteResponse(success=True) \ No newline at end of file diff --git a/backend/app/api/queries.py b/backend/app/api/queries.py index 2a3cee9..1ade055 100644 --- a/backend/app/api/queries.py +++ b/backend/app/api/queries.py @@ -3,6 +3,7 @@ import uuid from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.ext.asyncio import AsyncSession +from app.api.base import PaginationParams, PaginatedResponse from app.api.deps import get_current_user from app.database import get_db from app.models.user import User @@ -16,12 +17,15 @@ router = APIRouter() @router.get("/", response_model=QueryListResponse) async def list_queries( - skip: int = Query(0, ge=0), - limit: int = Query(20, ge=1, le=100), + pagination: PaginationParams = Depends(PaginationParams), db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): - items, total = await get_queries(db, current_user.id, skip=skip, limit=limit) + items, total = await get_queries( + db, current_user.id, + skip=pagination.offset, + limit=pagination.limit, + ) return {"items": items, "total": total} diff --git a/backend/app/config.py b/backend/app/config.py index d0e45cd..3526994 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -1,5 +1,8 @@ +import sys from pathlib import Path +from pydantic import field_validator, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict +from typing import Optional _env_path = Path(__file__).resolve().parent.parent.parent / ".env" if not _env_path.exists(): @@ -11,10 +14,15 @@ class Settings(BaseSettings): DATABASE_URL: str = "postgresql+asyncpg://postgres:postgres123@db:5432/geo_platform" REDIS_URL: str = "redis://redis:6379/0" - JWT_SECRET: str = "your-secret-key-change-in-production" + + # JWT 密钥:必须通过环境变量设置,不提供任何默认值 + JWT_SECRET: str JWT_EXPIRE_HOURS: int = 24 + + # NextAuth 密钥 + SECRET_KEY: Optional[str] = None + PLAYWRIGHT_BROWSERS_PATH: str = "/ms-playwright" - DEEPSEEK_API_KEY: str = "" ENABLE_LLM: bool = False ZHIPU_API_KEY: str = "" TONGYI_API_KEY: str = "" @@ -41,5 +49,36 @@ class Settings(BaseSettings): # AI平台API调用频率限制(每分钟请求数) API_RATE_LIMIT_RPM: int = 10 + @field_validator("JWT_SECRET") + @classmethod + def validate_jwt_secret(cls, v: str) -> str: + if not v or v.strip() == "": + print( + "[FATAL] JWT_SECRET is not set. " + "Please set a strong secret key (>= 32 characters) in your .env file.", + file=sys.stderr, + ) + sys.exit(1) + if len(v) < 32: + print( + f"[FATAL] JWT_SECRET is too short ({len(v)} chars). " + "It must be at least 32 characters long.", + file=sys.stderr, + ) + sys.exit(1) + return v + + @model_validator(mode="after") + def validate_secret_key(self) -> "Settings": + if self.SECRET_KEY is not None: + if len(self.SECRET_KEY) < 32: + print( + f"[FATAL] SECRET_KEY is too short ({len(self.SECRET_KEY)} chars). " + "It must be at least 32 characters long.", + file=sys.stderr, + ) + sys.exit(1) + return self + settings = Settings() diff --git a/backend/app/database.py b/backend/app/database.py index bb4ba82..0adc019 100644 --- a/backend/app/database.py +++ b/backend/app/database.py @@ -1,12 +1,17 @@ from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession from sqlalchemy.orm import declarative_base +from sqlalchemy import text from app.config import settings engine = create_async_engine( settings.DATABASE_URL, - echo=False, - future=True, + pool_size=10, # 连接池大小 + max_overflow=20, # 最大溢出连接数 + pool_timeout=30, # 等待连接超时(秒) + pool_recycle=3600, # 连接回收时间(1小时) + pool_pre_ping=True, # 使用前 ping 检查连接有效性 + echo=False, # 生产环境关闭 SQL echo ) AsyncSessionLocal = async_sessionmaker( @@ -26,3 +31,13 @@ async def get_db() -> AsyncSession: yield session finally: await session.close() + + +async def check_db_connection() -> bool: + """检查数据库连接是否正常""" + try: + async with AsyncSessionLocal() as session: + await session.execute(text("SELECT 1")) + return True + except Exception: + return False diff --git a/backend/app/logging_config.py b/backend/app/logging_config.py new file mode 100644 index 0000000..ec555f5 --- /dev/null +++ b/backend/app/logging_config.py @@ -0,0 +1,57 @@ +"""结构化 JSON 日志配置模块。""" +import logging +import json +from datetime import datetime, timezone + + +class JSONFormatter(logging.Formatter): + """将日志记录格式化为 JSON 字符串,便于日志收集平台(如 ELK、Loki)解析。""" + + def format(self, record: logging.LogRecord) -> str: + log_entry: dict = { + "timestamp": datetime.now(timezone.utc).isoformat(), + "level": record.levelname, + "message": record.getMessage(), + "logger": record.name, + "module": record.module, + "function": record.funcName, + "line": record.lineno, + } + + if record.exc_info: + log_entry["exception"] = self.formatException(record.exc_info) + + # 从 extra 字段注入的可观测性上下文 + if hasattr(record, "user_id"): + log_entry["user_id"] = record.user_id + if hasattr(record, "request_id"): + log_entry["request_id"] = record.request_id + if hasattr(record, "path"): + log_entry["path"] = record.path + if hasattr(record, "method"): + log_entry["method"] = record.method + if hasattr(record, "duration_ms"): + log_entry["duration_ms"] = record.duration_ms + if hasattr(record, "status_code"): + log_entry["status_code"] = record.status_code + + return json.dumps(log_entry, ensure_ascii=False) + + +def setup_logging(level: int = logging.INFO) -> None: + """初始化全局 JSON 日志配置。 + + 应在应用启动时(import 其他模块之前)调用一次。 + """ + handler = logging.StreamHandler() + handler.setFormatter(JSONFormatter()) + + root_logger = logging.getLogger() + # 清空已有 handlers,避免重复输出 + root_logger.handlers.clear() + root_logger.addHandler(handler) + root_logger.setLevel(level) + + # 降低 uvicorn/sqlalchemy 等第三方库的噪音 + logging.getLogger("uvicorn.access").setLevel(logging.WARNING) + logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) diff --git a/backend/app/main.py b/backend/app/main.py index 12b1d98..9b0b29f 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,12 +1,17 @@ import logging from contextlib import asynccontextmanager +from datetime import datetime, timezone -from fastapi import FastAPI +from fastapi import FastAPI, HTTPException, Request, Depends +from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import text + +# 必须在其他模块 import 之前初始化 JSON 日志 +from app.logging_config import setup_logging +setup_logging() -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s [%(name)s] %(levelname)s: %(message)s" -) from fastapi.middleware.cors import CORSMiddleware from app.api.admin import router as admin_router @@ -23,10 +28,18 @@ from app.api.citations import router as citations_router from app.api.queries import router as queries_router from app.api.reports import router as reports_router from app.api.subscriptions import router as subscription_router +from app.api.alerts import router as alerts_router +from app.api.dashboard import router as dashboard_router +from app.api.brands import router as brands_router +from app.api.onboarding import router as onboarding_router from app.config import settings from app.database import engine, Base +from app.schemas.common import ErrorResponse, ErrorCode from app.middleware.rate_limit import RateLimitMiddleware from app.middleware.logging_middleware import RequestLoggingMiddleware +from app.middleware.request_id import RequestIdMiddleware +from app.middleware.metrics import MetricsMiddleware +from app.database import get_db from app.workers.scheduler import query_scheduler @@ -50,6 +63,45 @@ app = FastAPI( lifespan=lifespan, ) + +@app.exception_handler(HTTPException) +async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse: + """统一 HTTP 异常响应格式。""" + code = ErrorCode.from_status(exc.status_code) + return JSONResponse( + status_code=exc.status_code, + content=ErrorResponse( + detail=str(exc.detail), + code=code, + ).model_dump(mode="json"), + ) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse: + """统一参数校验异常响应格式。""" + return JSONResponse( + status_code=422, + content=ErrorResponse( + detail="请求参数校验失败", + code=ErrorCode.VALIDATION_ERROR, + extra={"errors": exc.errors()}, + ).model_dump(mode="json"), + ) + + +@app.exception_handler(Exception) +async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse: + """兜底异常处理器,避免内部错误泄漏给客户端。""" + logging.getLogger(__name__).exception("Unhandled exception: %s", exc) + return JSONResponse( + status_code=500, + content=ErrorResponse( + detail="服务器内部错误,请稍后重试", + code=ErrorCode.INTERNAL_ERROR, + ).model_dump(mode="json"), + ) + _allow_origins = [origin.strip() for origin in settings.CORS_ORIGINS.split(",") if origin.strip()] if not _allow_origins: _allow_origins = ["http://localhost:3000"] @@ -72,11 +124,12 @@ async def add_security_headers(request, call_next): response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin" return response -# 限流中间件 -app.add_middleware(RateLimitMiddleware) - -# 请求日志中间件 +# 中间件注册顺序(FastAPI 后进先出,最后注册的最先执行) +# 执行链:RequestId → Metrics → RateLimit → RequestLogging → CORS → SecurityHeaders app.add_middleware(RequestLoggingMiddleware) +app.add_middleware(RateLimitMiddleware) +app.add_middleware(MetricsMiddleware) +app.add_middleware(RequestIdMiddleware) app.include_router(auth_router, prefix="/api/v1/auth", tags=["认证"]) app.include_router(queries_router, prefix="/api/v1/queries", tags=["查询词"]) @@ -92,8 +145,57 @@ app.include_router(contents_router, prefix="/api/v1/contents", tags=["内容管 app.include_router(clients_router, prefix="/api/v1/clients", tags=["客户管理"]) app.include_router(distribution_router, prefix="/api/v1/distribution", tags=["内容分发"]) app.include_router(analytics_router, prefix="/api/v1/analytics", tags=["监测优化"]) +app.include_router(alerts_router, prefix="/api/v1/alerts", tags=["告警通知"]) +app.include_router(dashboard_router, prefix="/api/v1/dashboard", tags=["仪表盘"]) +app.include_router(brands_router, prefix="/api/v1/brands", tags=["品牌管理"]) +app.include_router(onboarding_router, prefix="/api/v1") -@app.get("/health") +@app.get("/health", tags=["可观测性"]) async def health_check(): - return {"status": "ok"} + """存活检查(Liveness):服务进程是否运行正常。不依赖外部服务。""" + return { + "status": "healthy", + "timestamp": datetime.now(timezone.utc).isoformat(), + } + + +@app.get("/ready", tags=["可观测性"]) +async def readiness_check(db: AsyncSession = Depends(get_db)): + """就绪检查(Readiness):依赖服务(DB / Redis)是否就绪。 + + 供 Kubernetes readinessProbe / Docker healthcheck 使用。 + 不需要认证。 + """ + import redis.asyncio as aioredis # type: ignore + from app.config import settings as _settings + + # --- 检查数据库 --- + try: + await db.execute(text("SELECT 1")) + db_ok = True + except Exception: + db_ok = False + + # --- 检查 Redis --- + redis_ok = False + try: + redis_client = aioredis.from_url(_settings.REDIS_URL, socket_connect_timeout=2) + await redis_client.ping() + await redis_client.aclose() + redis_ok = True + except Exception: + pass + + all_ok = db_ok and redis_ok + return JSONResponse( + status_code=200 if all_ok else 503, + content={ + "status": "ready" if all_ok else "not_ready", + "checks": { + "database": "ok" if db_ok else "error", + "redis": "ok" if redis_ok else "error", + }, + "timestamp": datetime.now(timezone.utc).isoformat(), + }, + ) diff --git a/backend/app/middleware/metrics.py b/backend/app/middleware/metrics.py new file mode 100644 index 0000000..c87b97a --- /dev/null +++ b/backend/app/middleware/metrics.py @@ -0,0 +1,60 @@ +"""请求指标收集中间件:计时、慢请求告警、响应时间响应头。""" +import time +import logging +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from starlette.responses import Response + +logger = logging.getLogger("geo.metrics") + +# 慢请求阈值(秒) +SLOW_REQUEST_THRESHOLD = 1.0 + +# 跳过指标收集的路径前缀(健康检查等高频低价值路径) +_SKIP_PATHS = {"/health", "/ready", "/docs", "/openapi.json", "/favicon.ico"} + + +class MetricsMiddleware(BaseHTTPMiddleware): + """记录每个 HTTP 请求的耗时,并: + - 在响应头写入 X-Response-Time + - 对超过阈值的慢请求输出 WARNING 日志(携带结构化字段) + - 预留 Sentry / Prometheus 集成点(TODO 注释标注) + """ + + async def dispatch(self, request: Request, call_next) -> Response: + # 跳过健康检查等低价值路径,避免日志噪音 + if request.url.path in _SKIP_PATHS: + return await call_next(request) + + start_time = time.perf_counter() + response = await call_next(request) + duration = time.perf_counter() - start_time + duration_ms = round(duration * 1000, 2) + + # 写回响应时间响应头 + response.headers["X-Response-Time"] = f"{duration:.3f}s" + + # 从 request.state 获取 request_id(由 RequestIdMiddleware 注入) + request_id = getattr(request.state, "request_id", None) + + log_extra: dict = { + "path": request.url.path, + "method": request.method, + "duration_ms": duration_ms, + "status_code": response.status_code, + } + if request_id: + log_extra["request_id"] = request_id + + if duration >= SLOW_REQUEST_THRESHOLD: + logger.warning("Slow request detected", extra=log_extra) + else: + logger.debug("Request completed", extra=log_extra) + + # TODO: 集成 Prometheus Counter/Histogram + # metrics_registry.http_request_duration.observe(duration, labels={...}) + + # TODO: 集成 Sentry 性能监控 + # if sentry_sdk: sentry_sdk.set_measurement("response_time_ms", duration_ms) + + return response diff --git a/backend/app/middleware/rate_limit.py b/backend/app/middleware/rate_limit.py index 8037270..e41f2dc 100644 --- a/backend/app/middleware/rate_limit.py +++ b/backend/app/middleware/rate_limit.py @@ -7,6 +7,26 @@ from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request from starlette.responses import JSONResponse + +def _extract_user_id_from_request(request: Request) -> str | None: + """尝试从 Authorization header 解析 user_id(JWT sub)。 + 解析失败时返回 None,不影响主流程。 + """ + auth_header = request.headers.get("authorization", "") + if not auth_header.startswith("Bearer "): + return None + token = auth_header[len("Bearer "):] + if not token: + return None + try: + from app.services.auth import verify_token + payload = verify_token(token) + user_id: str | None = payload.get("sub") + return user_id + except Exception: + return None + + class RateLimitMiddleware(BaseHTTPMiddleware): def __init__(self, app): super().__init__(app) @@ -15,9 +35,14 @@ class RateLimitMiddleware(BaseHTTPMiddleware): # 限流规则 self.rules = { - "auth": { # /api/v1/auth/login, register, forgot-password - "paths": ["/api/v1/auth/login", "/api/v1/auth/register", "/api/v1/auth/forgot-password"], - "max_requests": 100, + "auth_strict": { # /api/v1/auth/login, register - 严格限流 5次/分钟/IP + "paths": ["/api/v1/auth/login", "/api/v1/auth/register"], + "max_requests": 5, + "window_seconds": 60, + }, + "auth": { # /api/v1/auth/ 其余接口 + "paths": ["/api/v1/auth/forgot-password", "/api/v1/auth/refresh"], + "max_requests": 20, "window_seconds": 60, }, "query_run": { # run-now @@ -35,37 +60,55 @@ class RateLimitMiddleware(BaseHTTPMiddleware): client_ip = request.client.host if request.client else "unknown" path = request.url.path now = time.time() - + # 健康检查不限流 if path == "/health" or path.startswith("/docs") or path.startswith("/openapi"): return await call_next(request) - - # 检查认证接口限流 - if any(path == p for p in self.rules["auth"]["paths"]): + + # 尝试从 Authorization header 解析 user_id + user_id = _extract_user_id_from_request(request) + + # 检查严格限流认证接口(login/register:5次/分钟/IP) + if any(path == p for p in self.rules["auth_strict"]["paths"]): + key = f"auth_strict:{client_ip}" + if self._is_rate_limited(key, now, self.rules["auth_strict"]): + return JSONResponse( + status_code=429, + content={"detail": "请求过于频繁,请稍后再试"} + ) + + # 检查普通认证接口限流 + elif any(path == p for p in self.rules["auth"]["paths"]): key = f"auth:{client_ip}" if self._is_rate_limited(key, now, self.rules["auth"]): return JSONResponse( status_code=429, content={"detail": "请求过于频繁,请稍后再试"} ) - - # 检查查询执行限流 + + # 检查查询执行限流(基于用户ID+IP组合) if path.endswith("/run-now") and request.method == "POST": - key = f"query_run:{client_ip}" + if user_id: + key = f"query_run:{user_id}:{client_ip}" + else: + key = f"query_run:{client_ip}" if self._is_rate_limited(key, now, self.rules["query_run"]): return JSONResponse( status_code=429, content={"detail": "查询执行过于频繁,请稍后再试"} ) - - # 全局限流 - key = f"global:{client_ip}" + + # 全局限流(基于用户ID+IP组合,未认证请求按IP限流) + if user_id: + key = f"global:{user_id}:{client_ip}" + else: + key = f"global:{client_ip}" if self._is_rate_limited(key, now, self.rules["global"]): return JSONResponse( status_code=429, content={"detail": "请求过于频繁,请稍后再试"} ) - + return await call_next(request) def _is_rate_limited(self, key, now, rule): diff --git a/backend/app/middleware/request_id.py b/backend/app/middleware/request_id.py new file mode 100644 index 0000000..a66a6d3 --- /dev/null +++ b/backend/app/middleware/request_id.py @@ -0,0 +1,29 @@ +"""Request ID 中间件:为每个请求生成并传播唯一标识符。""" +import uuid +import logging +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from starlette.responses import Response + +logger = logging.getLogger("geo.request_id") + +REQUEST_ID_HEADER = "X-Request-ID" + + +class RequestIdMiddleware(BaseHTTPMiddleware): + """从请求头读取或自动生成 X-Request-ID,注入 request.state 并写回响应头。 + + 使用场景: + - 链路追踪:日志中携带 request_id 方便跨服务排查 + - 客户端可主动传入 X-Request-ID,实现端到端追踪 + """ + + async def dispatch(self, request: Request, call_next) -> Response: + request_id = request.headers.get(REQUEST_ID_HEADER) or str(uuid.uuid4()) + + # 注入到 request.state,业务代码可通过 request.state.request_id 读取 + request.state.request_id = request_id + + response = await call_next(request) + response.headers[REQUEST_ID_HEADER] = request_id + return response diff --git a/backend/app/schemas/auth.py b/backend/app/schemas/auth.py index 777bbca..e047470 100644 --- a/backend/app/schemas/auth.py +++ b/backend/app/schemas/auth.py @@ -58,4 +58,16 @@ class UserResponse(BaseModel): class TokenResponse(BaseModel): access_token: str token_type: str + refresh_token: str user: UserResponse + + +class RefreshTokenRequest(BaseModel): + refresh_token: str + + +class AccessTokenResponse(BaseModel): + """刷新接口返回:新 access_token + 新 refresh_token(滑动过期)""" + access_token: str + token_type: str + refresh_token: str diff --git a/backend/app/schemas/common.py b/backend/app/schemas/common.py new file mode 100644 index 0000000..f0caebf --- /dev/null +++ b/backend/app/schemas/common.py @@ -0,0 +1,45 @@ +"""通用响应 Schema。""" +from datetime import datetime +from typing import Any + +from pydantic import BaseModel, Field + + +class ErrorResponse(BaseModel): + """统一错误响应格式。""" + + detail: str + code: str # 如 "NOT_FOUND", "VALIDATION_ERROR", "INTERNAL_ERROR", "FORBIDDEN" + timestamp: datetime = Field(default_factory=datetime.utcnow) + extra: dict[str, Any] | None = None + + model_config = {"from_attributes": True} + + +# 常用错误码常量 +class ErrorCode: + NOT_FOUND = "NOT_FOUND" + VALIDATION_ERROR = "VALIDATION_ERROR" + INTERNAL_ERROR = "INTERNAL_ERROR" + FORBIDDEN = "FORBIDDEN" + UNAUTHORIZED = "UNAUTHORIZED" + CONFLICT = "CONFLICT" + BAD_REQUEST = "BAD_REQUEST" + RATE_LIMITED = "RATE_LIMITED" + + # HTTP 状态码 → 错误码 映射 + STATUS_CODE_MAP: dict[int, str] = { + 400: "BAD_REQUEST", + 401: "UNAUTHORIZED", + 403: "FORBIDDEN", + 404: "NOT_FOUND", + 409: "CONFLICT", + 422: "VALIDATION_ERROR", + 429: "RATE_LIMITED", + 500: "INTERNAL_ERROR", + 503: "SERVICE_UNAVAILABLE", + } + + @classmethod + def from_status(cls, status_code: int) -> str: + return cls.STATUS_CODE_MAP.get(status_code, "INTERNAL_ERROR") diff --git a/backend/app/schemas/lifecycle.py b/backend/app/schemas/lifecycle.py index e462769..32c8225 100644 --- a/backend/app/schemas/lifecycle.py +++ b/backend/app/schemas/lifecycle.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime -from pydantic import BaseModel +from pydantic import BaseModel, model_validator # ---------- Request ---------- @@ -36,10 +36,12 @@ class StageDetailResponse(BaseModel): class ProjectResponse(BaseModel): id: uuid.UUID organization_id: uuid.UUID + name: str = "" # alias for brand_name for frontend compatibility brand_name: str brand_aliases: list - current_stage: int + current_stage: str # mapped from int to string ("diagnosis" etc) for frontend status: str + owner_id: uuid.UUID | None = None # alias for created_by for frontend created_by: uuid.UUID | None created_at: datetime updated_at: datetime @@ -47,11 +49,39 @@ class ProjectResponse(BaseModel): model_config = {"from_attributes": True} + @model_validator(mode="before") + @classmethod + def map_fields(cls, data): + # Handle SQLAlchemy model instance + if hasattr(data, "current_stage"): + stage_int = getattr(data, "current_stage", 1) + stage_map = {1: "diagnosis", 2: "strategy", 3: "content", 4: "publishing", 5: "monitoring"} + if isinstance(stage_int, int): + object.__setattr__(data, "current_stage", stage_map.get(stage_int, "diagnosis")) + # Set name = brand_name for frontend + if not getattr(data, "name", None): + object.__setattr__(data, "name", getattr(data, "brand_name", "")) + # Set owner_id = created_by for frontend + if not getattr(data, "owner_id", None): + object.__setattr__(data, "owner_id", getattr(data, "created_by", None)) + elif isinstance(data, dict): + stage_val = data.get("current_stage", 1) + stage_map = {1: "diagnosis", 2: "strategy", 3: "content", 4: "publishing", 5: "monitoring"} + if isinstance(stage_val, int): + data["current_stage"] = stage_map.get(stage_val, "diagnosis") + data.setdefault("name", data.get("brand_name", "")) + data.setdefault("owner_id", data.get("created_by")) + return data + class ProjectStatsResponse(BaseModel): total_projects: int active_projects: int - stage_distribution: dict[str, int] + completed_projects: int = 0 + contents_produced: int = 0 + avg_ai_citation_rate: float | None = None + current_stage_distribution: dict[str, int] = {} + stage_distribution: dict[str, int] = {} completion_rate: float diff --git a/backend/app/services/admin.py b/backend/app/services/admin.py index d459aa3..252ab8d 100644 --- a/backend/app/services/admin.py +++ b/backend/app/services/admin.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime, timedelta -from sqlalchemy import func, select +from sqlalchemy import func, select, case from sqlalchemy.ext.asyncio import AsyncSession from app.models.citation_record import CitationRecord @@ -64,17 +64,26 @@ async def get_users( base_stmt = base_stmt.order_by(User.created_at.desc()).offset(skip).limit(limit) result = await db.execute(base_stmt) - users = result.scalars().all() + users = list(result.scalars().all()) count_result = await db.execute(count_stmt) total = count_result.scalar_one() + if not users: + return {"items": [], "total": total} + + # 修复 N+1:一次性批量获取所有用户的 query 计数 + user_ids = [u.id for u in users] + query_count_stmt = ( + select(Query.user_id, func.count().label("cnt")) + .where(Query.user_id.in_(user_ids)) + .group_by(Query.user_id) + ) + qc_result = await db.execute(query_count_stmt) + query_counts: dict = {row.user_id: row.cnt for row in qc_result.all()} + items = [] for user in users: - query_count_result = await db.execute( - select(func.count()).select_from(Query).where(Query.user_id == user.id) - ) - query_count = query_count_result.scalar_one() items.append( { "id": user.id, @@ -84,7 +93,7 @@ async def get_users( "is_active": user.is_active, "is_admin": user.is_admin, "email_verified": user.email_verified, - "query_count": query_count, + "query_count": query_counts.get(user.id, 0), "created_at": user.created_at, } ) diff --git a/backend/app/services/auth.py b/backend/app/services/auth.py index a41a0d5..6b37ed3 100644 --- a/backend/app/services/auth.py +++ b/backend/app/services/auth.py @@ -25,14 +25,41 @@ def verify_password(plain_password: str, hashed_password: str) -> bool: def create_access_token(data: dict) -> str: to_encode = data.copy() - expire = datetime.utcnow() + timedelta(hours=settings.JWT_EXPIRE_HOURS) - to_encode.update({"exp": expire}) + # access token 有效期固定为 1 小时(替代原来的 JWT_EXPIRE_HOURS=24h) + expire = datetime.utcnow() + timedelta(hours=1) + to_encode.update({"exp": expire, "type": "access"}) encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm="HS256") return encoded_jwt +def create_refresh_token(data: dict) -> str: + """7 天有效期的刷新令牌,使用 type: 'refresh' 区分""" + to_encode = data.copy() + expire = datetime.utcnow() + timedelta(days=7) + to_encode.update({"exp": expire, "type": "refresh"}) + encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm="HS256") + return encoded_jwt + + +def verify_refresh_token(token: str) -> dict: + """验证 refresh token,返回 payload;如果无效或类型不匹配则抛出异常""" + try: + payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"]) + except JWTError: + raise ValueError("刷新令牌无效") + if payload.get("type") != "refresh": + raise ValueError("令牌类型错误") + return payload + + def verify_token(token: str) -> dict: - payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"]) + """验证 access token,返回 payload""" + try: + payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"]) + except JWTError: + raise ValueError("访问令牌无效") + if payload.get("type") not in ("access", None): # None 兼容旧 token + raise ValueError("令牌类型错误") return payload diff --git a/backend/app/services/cache.py b/backend/app/services/cache.py new file mode 100644 index 0000000..e078739 --- /dev/null +++ b/backend/app/services/cache.py @@ -0,0 +1,106 @@ +"""Redis 缓存服务层。 + +提供统一的缓存读写接口,供各 API 端点使用: +- 品牌列表(TTL: 5 分钟) +- 仪表盘统计数据(TTL: 2 分钟) +- 用户配置信息(TTL: 10 分钟) +""" +import json +import logging +from typing import Any + +import redis.asyncio as aioredis + +from app.config import settings + +logger = logging.getLogger(__name__) + +# TTL 常量(秒) +TTL_BRANDS = 300 # 5 分钟 +TTL_DASHBOARD = 120 # 2 分钟 +TTL_USER_PROFILE = 600 # 10 分钟 + + +class CacheService: + """异步 Redis 缓存服务。""" + + def __init__(self) -> None: + self._redis: aioredis.Redis | None = None + + @property + def redis(self) -> aioredis.Redis: + if self._redis is None: + self._redis = aioredis.from_url( + settings.REDIS_URL, + encoding="utf-8", + decode_responses=True, + ) + return self._redis + + async def get(self, key: str) -> str | None: + """从缓存读取字符串值,不存在或出错时返回 None。""" + try: + return await self.redis.get(key) + except Exception as exc: + logger.warning("Cache GET failed for key=%s: %s", key, exc) + return None + + async def get_json(self, key: str) -> Any | None: + """从缓存读取并反序列化 JSON 值。""" + raw = await self.get(key) + if raw is None: + return None + try: + return json.loads(raw) + except json.JSONDecodeError: + return None + + async def set(self, key: str, value: str, expire: int = 300) -> None: + """写入缓存字符串值,expire 单位为秒。""" + try: + await self.redis.set(key, value, ex=expire) + except Exception as exc: + logger.warning("Cache SET failed for key=%s: %s", key, exc) + + async def set_json(self, key: str, value: Any, expire: int = 300) -> None: + """序列化为 JSON 后写入缓存。""" + try: + await self.set(key, json.dumps(value, default=str), expire=expire) + except Exception as exc: + logger.warning("Cache SET_JSON failed for key=%s: %s", key, exc) + + async def delete(self, key: str) -> None: + """删除指定缓存键。""" + try: + await self.redis.delete(key) + except Exception as exc: + logger.warning("Cache DELETE failed for key=%s: %s", key, exc) + + async def invalidate_pattern(self, pattern: str) -> int: + """批量删除匹配 pattern 的所有缓存键,返回删除数量。""" + try: + keys = await self.redis.keys(pattern) + if keys: + return await self.redis.delete(*keys) + return 0 + except Exception as exc: + logger.warning("Cache INVALIDATE_PATTERN failed for pattern=%s: %s", pattern, exc) + return 0 + + async def close(self) -> None: + """关闭 Redis 连接。""" + if self._redis is not None: + await self._redis.aclose() + self._redis = None + + +# 模块级单例(懒加载,应用启动后自动创建连接池) +_cache_service: CacheService | None = None + + +def get_cache_service() -> CacheService: + """获取全局缓存服务单例。""" + global _cache_service + if _cache_service is None: + _cache_service = CacheService() + return _cache_service diff --git a/backend/app/services/citation.py b/backend/app/services/citation.py index a1fd4be..fa27d48 100644 --- a/backend/app/services/citation.py +++ b/backend/app/services/citation.py @@ -289,6 +289,7 @@ async def trigger_query_now( keyword=query.keyword, target_brand=query.target_brand, brand_aliases=query.brand_aliases or [], + user_id=user_id, ) ) @@ -301,11 +302,19 @@ async def _execute_query_tasks( keyword: str, target_brand: str, brand_aliases: list, + user_id: uuid.UUID | None = None, ): """后台执行查询任务""" engine = CitationEngine() try: async with AsyncSessionLocal() as db: + # 验证 query 归属该用户 + if user_id is not None: + query = await _verify_query_ownership(db, query_id, user_id) + if query is None: + logger.error(f"查询 {query_id} 不属于用户 {user_id},跳过执行") + return + stmt = select(QueryTask).where( QueryTask.query_id == query_id, QueryTask.status == "pending", diff --git a/backend/app/services/knowledge/rag_service.py b/backend/app/services/knowledge/rag_service.py index 403f9b5..3045388 100644 --- a/backend/app/services/knowledge/rag_service.py +++ b/backend/app/services/knowledge/rag_service.py @@ -23,7 +23,16 @@ class RAGService: def __init__(self, embedder: Optional[EmbeddingService] = None): self.chunker = RecursiveChunker() - self.embedder = embedder or MockEmbedder() # 默认 mock,生产注入 OpenAIEmbedder + if embedder is not None: + self.embedder = embedder + else: + from app.config import settings + if settings.OPENAI_API_KEY: + from app.services.knowledge.embedder import OpenAIEmbedder + self.embedder = OpenAIEmbedder(api_key=settings.OPENAI_API_KEY) + else: + logger.warning("未配置 OPENAI_API_KEY,知识库将使用 MockEmbedder(仅适用于开发环境)") + self.embedder = MockEmbedder() self.retriever = HybridRetriever(self.embedder) # ------------------------------------------------------------------ diff --git a/backend/app/services/llm/__init__.py b/backend/app/services/llm/__init__.py index 589e239..6b7414d 100644 --- a/backend/app/services/llm/__init__.py +++ b/backend/app/services/llm/__init__.py @@ -2,6 +2,7 @@ from .base import LLMError, LLMProvider, LLMResponse from .deepseek_provider import DeepSeekProvider from .factory import LLMFactory from .openai_provider import OpenAIProvider +from .rate_limiter import TokenBucketRateLimiter, get_rate_limiter __all__ = [ "LLMProvider", @@ -10,4 +11,6 @@ __all__ = [ "LLMFactory", "OpenAIProvider", "DeepSeekProvider", + "TokenBucketRateLimiter", + "get_rate_limiter", ] diff --git a/backend/app/services/llm/deepseek_provider.py b/backend/app/services/llm/deepseek_provider.py index 581b68b..0e41b4e 100644 --- a/backend/app/services/llm/deepseek_provider.py +++ b/backend/app/services/llm/deepseek_provider.py @@ -6,6 +6,7 @@ from typing import AsyncIterator import httpx from .base import LLMError, LLMProvider, LLMResponse +from .rate_limiter import get_rate_limiter _DEFAULT_MODEL = "deepseek-chat" _DEFAULT_MAX_CONTEXT = 64_000 @@ -111,6 +112,9 @@ class DeepSeekProvider(LLMProvider): async def _request_with_retry(self, payload: dict, *, stream: bool = False) -> dict: """带重试的请求(指数退避:1s, 2s, 4s)""" + # 全局速率限制 + await get_rate_limiter().acquire() + last_error: Exception | None = None for attempt in range(_MAX_RETRIES): @@ -149,6 +153,9 @@ class DeepSeekProvider(LLMProvider): async def _stream_request(self, payload: dict) -> AsyncIterator[str]: """SSE流式请求(OpenAI兼容格式)""" + # 全局速率限制 + await get_rate_limiter().acquire() + last_error: Exception | None = None for attempt in range(_MAX_RETRIES): diff --git a/backend/app/services/llm/openai_provider.py b/backend/app/services/llm/openai_provider.py index 69aa956..ee5da81 100644 --- a/backend/app/services/llm/openai_provider.py +++ b/backend/app/services/llm/openai_provider.py @@ -6,6 +6,7 @@ from typing import AsyncIterator import httpx from .base import LLMError, LLMProvider, LLMResponse +from .rate_limiter import get_rate_limiter # 支持的模型及其上下文长度(百炼 Coding Plan + OpenAI) _OPENAI_MODELS: dict[str, int] = { @@ -126,6 +127,9 @@ class OpenAIProvider(LLMProvider): async def _request_with_retry(self, payload: dict, *, stream: bool = False) -> dict: """带重试的请求(指数退避:1s, 2s, 4s)""" + # 全局速率限制 + await get_rate_limiter().acquire() + last_error: Exception | None = None for attempt in range(_MAX_RETRIES): @@ -166,6 +170,9 @@ class OpenAIProvider(LLMProvider): async def _stream_request(self, payload: dict) -> AsyncIterator[str]: """SSE流式请求""" + # 全局速率限制 + await get_rate_limiter().acquire() + last_error: Exception | None = None for attempt in range(_MAX_RETRIES): diff --git a/backend/app/services/llm/rate_limiter.py b/backend/app/services/llm/rate_limiter.py new file mode 100644 index 0000000..c335645 --- /dev/null +++ b/backend/app/services/llm/rate_limiter.py @@ -0,0 +1,105 @@ +"""LLM 调用全局限速器(令牌桶算法) + +所有 LLMProvider 实例共享同一个 RateLimiter 单例, +确保跨 Provider 的总调用频率不超过配置上限。 +""" + +import asyncio +import logging +import os +import time +from collections import deque + +logger = logging.getLogger(__name__) + + +class TokenBucketRateLimiter: + """基于令牌桶算法的速率限制器 + + 默认 30 RPM(每秒补充约 0.5 个令牌),可通过环境变量 + LLM_RATE_LIMIT_RPM 调整。 + """ + + _instance: "TokenBucketRateLimiter | None" = None + _lock = asyncio.Lock() + + def __init__( + self, + max_rpm: float = 30.0, + ): + self._max_rpm = max_rpm + self._refill_rate = max_rpm / 60.0 # tokens per second + self._max_tokens = max_rpm + self._tokens = max_rpm # start full + self._last_refill = time.monotonic() + self._semaphore = asyncio.Semaphore(1) # 一次只能有一个 acquire 等待 + # 用于记录最近请求时间(调试/监控用) + self._recent_requests: deque[float] = deque(maxlen=int(max_rpm * 2)) + + @classmethod + def get_instance(cls) -> "TokenBucketRateLimiter": + """获取全局单例""" + if cls._instance is None: + rpm = float(os.getenv("LLM_RATE_LIMIT_RPM", "30")) + cls._instance = cls(max_rpm=rpm) + logger.info(f"LLM RateLimiter initialized: {rpm} RPM") + return cls._instance + + @classmethod + async def reset_instance(cls) -> None: + """重置单例(仅用于测试)""" + async with cls._lock: + if cls._instance is not None: + cls._instance = None + + def _refill(self) -> None: + """补充令牌""" + now = time.monotonic() + elapsed = now - self._last_refill + tokens_to_add = elapsed * self._refill_rate + self._tokens = min(self._max_tokens, self._tokens + tokens_to_add) + self._last_refill = now + + async def acquire(self) -> None: + """获取一个令牌,若无可用令牌则等待 + + 此方法可安全地从多个协程并发调用。 + """ + async with self._semaphore: + self._refill() + + if self._tokens >= 1.0: + self._tokens -= 1.0 + self._recent_requests.append(time.monotonic()) + return + + # 如果没有可用令牌,计算等待时间 + wait_time = (1.0 - self._tokens) / self._refill_rate + if wait_time > 0: + logger.debug(f"LLM rate limiter: waiting {wait_time:.2f}s for token") + await asyncio.sleep(wait_time) + + # 重试获取 + async with self._semaphore: + self._refill() + self._tokens = max(0.0, self._tokens - 1.0) + self._recent_requests.append(time.monotonic()) + + @property + def available_tokens(self) -> float: + """当前可用令牌数""" + return self._tokens + + @property + def max_rpm(self) -> float: + """配置的最大 RPM""" + return self._max_rpm + + +# 模块级便捷函数 +_rate_limiter: TokenBucketRateLimiter | None = None + + +def get_rate_limiter() -> TokenBucketRateLimiter: + """获取全局速率限制器实例""" + return TokenBucketRateLimiter.get_instance() diff --git a/backend/app/workers/llm_adapter.py b/backend/app/workers/llm_adapter.py index a996f18..be60a51 100644 --- a/backend/app/workers/llm_adapter.py +++ b/backend/app/workers/llm_adapter.py @@ -31,32 +31,47 @@ class LLMAdapterError(Exception): class LLMAdapter: - """LLM适配器 - 使用DeepSeek API检测品牌引用""" + """LLM适配器 - 使用 OpenAI 兼容协议检测品牌引用(支持百炼/DashScope/DeepSeek)""" def __init__(self, api_key: Optional[str] = None, max_retries: int = 3): """ 初始化LLM适配器 Args: - api_key: DeepSeek API密钥,默认使用settings中的配置 + api_key: API密钥,默认优先使用 OPENAI_API_KEY(百炼/DashScope),其次 DEEPSEEK_API_KEY max_retries: 最大重试次数 """ - self.api_key = api_key or getattr(settings, 'DEEPSEEK_API_KEY', None) + self.api_key = ( + api_key + or getattr(settings, 'OPENAI_API_KEY', None) + or getattr(settings, 'DEEPSEEK_API_KEY', None) + ) + # base_url 优先 OPENAI_BASE_URL,其次 DEEPSEEK_BASE_URL + self.base_url = ( + getattr(settings, 'OPENAI_BASE_URL', None) + or getattr(settings, 'DEEPSEEK_BASE_URL', 'https://api.deepseek.com/v1') + ) + # model 优先 OPENAI_MODEL,其次 DEFAULT_LLM_MODEL + self.model = ( + getattr(settings, 'OPENAI_MODEL', None) + or getattr(settings, 'DEFAULT_LLM_MODEL', 'qwen3-coder-plus') + or 'qwen3-coder-plus' + ) self.max_retries = max_retries self._client = None @property def client(self): - """延迟初始化DeepSeek客户端""" + """延迟初始化 OpenAI 兼容客户端""" if self._client is None: try: from openai import OpenAI self._client = OpenAI( api_key=self.api_key, - base_url="https://api.deepseek.com" + base_url=self.base_url, ) except ImportError: - raise LLMAdapterError("请安装deepseek-sdk或openai库: pip install deepseek-sdk") + raise LLMAdapterError("请安装openai库: pip install openai") return self._client def _build_prompt(self, keyword: str, brand_name: str, brand_aliases: list[str]) -> str: @@ -175,7 +190,7 @@ class LLMAdapter: API响应的JSON解析结果 """ response = self.client.chat.completions.create( - model="deepseek-chat", + model=self.model, messages=[ { "role": "user", diff --git a/backend/fix_citation_schema.py b/backend/fix_citation_schema.py new file mode 100644 index 0000000..6deb136 --- /dev/null +++ b/backend/fix_citation_schema.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Fix missing sentiment columns in citation_records table.""" + +import asyncio +import asyncpg + + +async def fix_schema(): + # Read DATABASE_URL from .env file in project root + db_url = "postgresql://chiguyong@localhost:5432/geo_platform" + + conn = await asyncpg.connect(db_url) + try: + # Check existing columns + rows = await conn.fetch( + "SELECT column_name FROM information_schema.columns WHERE table_name = 'citation_records'" + ) + existing = {r["column_name"] for r in rows} + print(f"Existing columns: {existing}") + + needed = ["sentiment", "sentiment_confidence", "sentiment_key_phrases"] + missing = [c for c in needed if c not in existing] + + if not missing: + print("All sentiment columns already exist.") + return + + print(f"Missing columns: {missing}") + + if "sentiment" in missing: + await conn.execute( + "ALTER TABLE citation_records ADD COLUMN sentiment VARCHAR(20) NULL" + ) + print("Added sentiment column") + + if "sentiment_confidence" in missing: + await conn.execute( + "ALTER TABLE citation_records ADD COLUMN sentiment_confidence DOUBLE PRECISION NULL" + ) + print("Added sentiment_confidence column") + + if "sentiment_key_phrases" in missing: + await conn.execute( + "ALTER TABLE citation_records ADD COLUMN sentiment_key_phrases JSONB NULL" + ) + print("Added sentiment_key_phrases column") + + print("Schema fix complete.") + finally: + await conn.close() + + +if __name__ == "__main__": + asyncio.run(fix_schema()) diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..cf5339b --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,17 @@ +[tool.ruff] +target-version = "py311" +line-length = 120 + +[tool.ruff.lint] +select = ["E", "W", "F", "I"] +ignore = ["E501"] + +[tool.ruff.lint.isort] +known-first-party = ["app"] + +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] diff --git a/backend/requirements.txt b/backend/requirements.txt index 20a8aaa..42b454a 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,6 +1,7 @@ # Web框架 fastapi>=0.109.0 uvicorn[standard] +gunicorn>=21.2.0 # 数据库 sqlalchemy>=2.0 diff --git a/backend/tests/test_performance.py b/backend/tests/test_performance.py new file mode 100644 index 0000000..ae9d0fa --- /dev/null +++ b/backend/tests/test_performance.py @@ -0,0 +1,381 @@ +"""Performance tests: concurrent access, response time, and rate limiting.""" +import asyncio +import time +import uuid + +import pytest +import pytest_asyncio +from httpx import AsyncClient, ASGITransport +from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession +from sqlalchemy.pool import StaticPool + +from app.database import Base +from app.main import app +from app.models.user import User +from app.models.query import Query +from app.models.brand import Brand +from app.models.competitor import Competitor +from app.models.suggestion import Suggestion +from app.api.deps import get_current_user, get_db +from app.services.auth import create_access_token, hash_password + +# Only the tables needed for performance tests (avoids JSONB/SQLite incompatibility) +_TEST_TABLES = ( + User.__table__, + Query.__table__, + Brand.__table__, + Competitor.__table__, + Suggestion.__table__, +) + + +# ─────────────────────── Fixtures ─────────────────────── + + +@pytest_asyncio.fixture +async def async_engine(): + """Create async engine for testing with SQLite. + + Only creates the specific tables needed by performance tests, + avoiding PostgreSQL-only types (JSONB) that fail on SQLite. + """ + engine = create_async_engine( + "sqlite+aiosqlite:///:memory:", + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) + async with engine.begin() as conn: + await conn.run_sync( + lambda sync_conn: Base.metadata.create_all( + sync_conn, tables=[t for t in _TEST_TABLES] + ) + ) + yield engine + await engine.dispose() + + +@pytest_asyncio.fixture +async def async_session(async_engine): + """Create async session for testing.""" + async_session_maker = async_sessionmaker( + async_engine, + class_=AsyncSession, + expire_on_commit=False, + autoflush=False, + autocommit=False, + ) + async with async_session_maker() as session: + yield session + + +@pytest_asyncio.fixture +async def test_user(async_session): + """Create a test user with properly hashed password.""" + user = User( + id=uuid.uuid4(), + email="perf_test@example.com", + password_hash=hash_password("PerfTest123!"), + name="Performance Test User", + plan="free", + max_queries=50, + is_active=True, + email_verified=True, + ) + async_session.add(user) + await async_session.commit() + await async_session.refresh(user) + return user + + +@pytest_asyncio.fixture +async def async_client(async_session, test_user): + """Create async client for API testing with dependency overrides.""" + session = async_session + + async def override_get_db(): + yield session + + async def override_get_current_user(): + return test_user + + app.dependency_overrides[get_db] = override_get_db + app.dependency_overrides[get_current_user] = override_get_current_user + + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + yield client + + app.dependency_overrides.clear() + + +@pytest_asyncio.fixture +async def client_no_override(async_session): + """Create async client WITHOUT overriding get_current_user (for real auth flow).""" + session = async_session + + async def override_get_db(): + yield session + + app.dependency_overrides[get_db] = override_get_db + + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + yield client + + app.dependency_overrides.clear() + + +@pytest.fixture +def auth_headers(test_user): + """Create authentication headers.""" + token = create_access_token(data={"sub": str(test_user.id)}) + return {"Authorization": f"Bearer {token}"} + + +# ═══════════════════════════════════════════════════════════ +# API Response Time Tests +# ═══════════════════════════════════════════════════════════ + + +class TestAPIPerformance: + """Test API response time and concurrency behavior.""" + + @pytest.mark.asyncio + async def test_health_check_fast(self, async_client): + """Health check endpoint should respond quickly (< 100ms).""" + start = time.time() + response = await async_client.get("/health") + elapsed = time.time() - start + assert response.status_code == 200 + assert elapsed < 0.1, f"Health check took {elapsed:.3f}s, expected < 0.1s" + + @pytest.mark.asyncio + async def test_brand_list_performance(self, async_client, async_session, test_user, auth_headers): + """Brand list API should respond within 500ms.""" + # Create several brands for a more realistic test + for i in range(10): + brand = Brand( + user_id=test_user.id, + name=f"Brand {i}", + platforms=["wenxin"], + status="active", + ) + async_session.add(brand) + await async_session.commit() + + start = time.time() + response = await async_client.get("/api/v1/brands/", headers=auth_headers) + elapsed = time.time() - start + + assert response.status_code == 200 + assert elapsed < 0.5, f"Brand list took {elapsed:.3f}s, expected < 0.5s" + + @pytest.mark.asyncio + async def test_query_list_performance(self, async_client, async_session, test_user, auth_headers): + """Query list API should respond within 500ms.""" + # Create several queries for a more realistic test + for i in range(10): + query = Query( + user_id=test_user.id, + keyword=f"query keyword {i}", + target_brand=f"Brand {i}", + platforms=["wenxin"], + status="active", + ) + async_session.add(query) + await async_session.commit() + + start = time.time() + response = await async_client.get("/api/v1/queries/", headers=auth_headers) + elapsed = time.time() - start + + assert response.status_code == 200 + assert elapsed < 0.5, f"Query list took {elapsed:.3f}s, expected < 0.5s" + + @pytest.mark.asyncio + async def test_me_endpoint_performance(self, async_client, auth_headers): + """Current user endpoint should respond within 200ms.""" + start = time.time() + response = await async_client.get("/api/v1/auth/me", headers=auth_headers) + elapsed = time.time() - start + + assert response.status_code == 200 + assert elapsed < 0.2, f"/auth/me took {elapsed:.3f}s, expected < 0.2s" + + +# ═══════════════════════════════════════════════════════════ +# Concurrency Tests +# ═══════════════════════════════════════════════════════════ + + +class TestConcurrency: + """Test concurrent access behavior.""" + + @pytest.mark.asyncio + async def test_concurrent_login_no_crash(self, client_no_override, test_user): + """50 concurrent login requests should not cause system crash. + + Note: Rate limiting will kick in after 5 attempts from same IP, + so most requests will get 429. The key point is no 500 errors. + """ + tasks = [] + for _ in range(50): + task = client_no_override.post( + "/api/v1/auth/login", + json={ + "email": "perf_test@example.com", + "password": "PerfTest123!", + }, + ) + tasks.append(task) + + responses = await asyncio.gather(*tasks, return_exceptions=True) + + for i, resp in enumerate(responses): + if isinstance(resp, Exception): + # Network/transport errors are acceptable under heavy load + continue + # Should NOT get 500 — rate limiting (429) or auth errors (401/422) are fine + assert resp.status_code in (200, 401, 422, 429), ( + f"Concurrent login request {i} returned {resp.status_code}, " + f"expected 200/401/422/429" + ) + + @pytest.mark.asyncio + async def test_concurrent_brand_reads(self, async_client, async_session, test_user, auth_headers): + """Concurrent brand list reads should all succeed.""" + # Pre-create data + for i in range(5): + brand = Brand( + user_id=test_user.id, + name=f"Concurrent Brand {i}", + platforms=["wenxin"], + status="active", + ) + async_session.add(brand) + await async_session.commit() + + # 20 concurrent read requests + tasks = [ + async_client.get("/api/v1/brands/", headers=auth_headers) + for _ in range(20) + ] + responses = await asyncio.gather(*tasks, return_exceptions=True) + + success_count = 0 + for resp in responses: + if isinstance(resp, Exception): + continue + if resp.status_code == 200: + success_count += 1 + + # At least some should succeed + assert success_count > 0, "No concurrent brand reads succeeded" + + @pytest.mark.asyncio + async def test_concurrent_query_reads(self, async_client, async_session, test_user, auth_headers): + """Concurrent query list reads should all succeed.""" + for i in range(5): + query = Query( + user_id=test_user.id, + keyword=f"concurrent query {i}", + target_brand=f"Brand {i}", + platforms=["wenxin"], + status="active", + ) + async_session.add(query) + await async_session.commit() + + tasks = [ + async_client.get("/api/v1/queries/", headers=auth_headers) + for _ in range(20) + ] + responses = await asyncio.gather(*tasks, return_exceptions=True) + + success_count = 0 + for resp in responses: + if isinstance(resp, Exception): + continue + if resp.status_code == 200: + success_count += 1 + + assert success_count > 0, "No concurrent query reads succeeded" + + +# ═══════════════════════════════════════════════════════════ +# Rate Limiting Tests +# ═══════════════════════════════════════════════════════════ + + +class TestRateLimiting: + """Test rate limiting enforcement.""" + + @pytest.mark.asyncio + async def test_login_rate_limit_enforcement(self, client_no_override): + """Login endpoint should enforce rate limiting (5 req/min/IP). + + After 5 rapid login attempts, subsequent requests should get 429. + """ + # Note: RateLimitMiddleware state is shared across the app instance. + # Since other tests may have already sent requests, we need to + # send enough to trigger the limit. The auth_strict rule allows + # 5 requests per 60 seconds per IP. + responses = [] + for _ in range(8): + response = await client_no_override.post( + "/api/v1/auth/login", + json={ + "email": "ratelimit@example.com", + "password": "somepassword123", + }, + ) + responses.append(response) + + # At least one of the later requests should be rate-limited (429) + status_codes = [r.status_code for r in responses] + # After 5 requests, additional ones should get 429 + rate_limited = [code for code in status_codes if code == 429] + assert len(rate_limited) > 0, ( + f"No rate limiting detected. Status codes: {status_codes}. " + f"Expected at least one 429 after 8 rapid login attempts." + ) + + @pytest.mark.asyncio + async def test_global_rate_limit_high_threshold(self, async_client, auth_headers): + """Global rate limit (100 req/min) should allow normal usage patterns. + + Sending 10 rapid requests should all succeed (well within limit). + """ + responses = [] + for _ in range(10): + response = await async_client.get("/health") + responses.append(response) + + # All should succeed — well under global limit + success_count = sum(1 for r in responses if r.status_code == 200) + assert success_count == 10, ( + f"Expected all 10 health checks to succeed, got {success_count}/10" + ) + + @pytest.mark.asyncio + async def test_rate_limit_429_response_format(self, client_no_override): + """Rate-limited responses should have proper 429 format.""" + # Exhaust login rate limit + for _ in range(8): + await client_no_override.post( + "/api/v1/auth/login", + json={"email": "rl@example.com", "password": "password123"}, + ) + + # This one should be rate-limited + response = await client_no_override.post( + "/api/v1/auth/login", + json={"email": "rl@example.com", "password": "password123"}, + ) + + if response.status_code == 429: + data = response.json() + # Should have a detail message + assert "detail" in data or "message" in data, ( + "429 response should include a detail or message field" + ) \ No newline at end of file diff --git a/backend/tests/test_security.py b/backend/tests/test_security.py new file mode 100644 index 0000000..e0ecfe4 --- /dev/null +++ b/backend/tests/test_security.py @@ -0,0 +1,667 @@ +"""Security tests: SQL injection, XSS protection, and authentication security.""" +import uuid +from datetime import datetime, timedelta + +import pytest +import pytest_asyncio +from httpx import AsyncClient, ASGITransport +from jose import jwt +from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession +from sqlalchemy.pool import StaticPool + +from app.database import Base +from app.main import app +from app.models.user import User +from app.models.brand import Brand +from app.models.query import Query +from app.models.competitor import Competitor +from app.models.suggestion import Suggestion +from app.api.deps import get_current_user, get_db +from app.services.auth import create_access_token, create_refresh_token, hash_password +from app.config import settings + +# Only the tables needed for security tests (avoids JSONB/SQLite incompatibility) +_TEST_TABLES = ( + User.__table__, + Brand.__table__, + Query.__table__, + Competitor.__table__, + Suggestion.__table__, +) + + +# ─────────────────────── Fixtures ─────────────────────── + + +@pytest_asyncio.fixture +async def async_engine(): + """Create async engine for testing with SQLite. + + Only creates the specific tables needed by security tests, + avoiding PostgreSQL-only types (JSONB) that fail on SQLite. + """ + engine = create_async_engine( + "sqlite+aiosqlite:///:memory:", + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) + async with engine.begin() as conn: + await conn.run_sync( + lambda sync_conn: Base.metadata.create_all( + sync_conn, tables=[t for t in _TEST_TABLES] + ) + ) + yield engine + await engine.dispose() + + +@pytest_asyncio.fixture +async def async_session(async_engine): + """Create async session for testing.""" + async_session_maker = async_sessionmaker( + async_engine, + class_=AsyncSession, + expire_on_commit=False, + autoflush=False, + autocommit=False, + ) + async with async_session_maker() as session: + yield session + + +@pytest_asyncio.fixture +async def test_user(async_session): + """Create a test user with properly hashed password.""" + user = User( + id=uuid.uuid4(), + email="security_test@example.com", + password_hash=hash_password("SecurePass123!"), + name="Security Test User", + plan="free", + max_queries=5, + is_active=True, + email_verified=True, + ) + async_session.add(user) + await async_session.commit() + await async_session.refresh(user) + return user + + +@pytest_asyncio.fixture +async def second_user(async_session): + """Create a second test user for cross-user isolation tests.""" + user = User( + id=uuid.uuid4(), + email="second_user@example.com", + password_hash=hash_password("SecondPass456!"), + name="Second User", + plan="free", + max_queries=5, + is_active=True, + email_verified=True, + ) + async_session.add(user) + await async_session.commit() + await async_session.refresh(user) + return user + + +@pytest_asyncio.fixture +async def async_client(async_session, test_user): + """Create async client for API testing with dependency overrides.""" + session = async_session + + async def override_get_db(): + yield session + + async def override_get_current_user(): + return test_user + + app.dependency_overrides[get_db] = override_get_db + app.dependency_overrides[get_current_user] = override_get_current_user + + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + yield client + + app.dependency_overrides.clear() + + +@pytest_asyncio.fixture +async def client_no_override(async_session): + """Create async client WITHOUT overriding get_current_user. + + This allows testing real JWT authentication flow. + get_db is still overridden to use test database. + """ + session = async_session + + async def override_get_db(): + yield session + + app.dependency_overrides[get_db] = override_get_db + # Intentionally NOT overriding get_current_user + + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + yield client + + app.dependency_overrides.clear() + + +@pytest.fixture +def auth_headers(test_user): + """Create authentication headers for test_user.""" + token = create_access_token(data={"sub": str(test_user.id)}) + return {"Authorization": f"Bearer {token}"} + + +@pytest.fixture +def second_auth_headers(second_user): + """Create authentication headers for second_user.""" + token = create_access_token(data={"sub": str(second_user.id)}) + return {"Authorization": f"Bearer {token}"} + + +# ═══════════════════════════════════════════════════════════ +# SQL Injection Protection Tests +# ═══════════════════════════════════════════════════════════ + + +class TestSQLInjection: + """Verify that SQL injection attack vectors are properly mitigated.""" + + @pytest.mark.asyncio + async def test_login_sql_injection_rejected(self, client_no_override): + """Login endpoint should reject SQL injection payloads. + + Email field uses EmailStr validation, so non-email payloads + should return 422 (validation error). The ORM layer uses + parameterized queries, preventing SQL injection even if + payloads pass validation. 429 (rate-limited) is also + acceptable — it means the security layer is working. + """ + payloads = [ + "' OR '1'='1", + "'; DROP TABLE users; --", + "admin'--", + "1' UNION SELECT * FROM users--", + "' OR 1=1 --", + '" OR ""=""', + "1; SELECT * FROM users WHERE '1' = '1'", + ] + for payload in payloads: + response = await client_no_override.post( + "/api/v1/auth/login", + json={"email": payload, "password": payload}, + ) + # 422: EmailStr validation rejects non-email strings + # 401: If valid email format but auth fails + # 429: Rate-limited (also a correct security behavior) + assert response.status_code in (401, 422, 429), ( + f"SQL injection payload '{payload}' returned {response.status_code}, " + f"expected 401/422/429" + ) + + @pytest.mark.asyncio + async def test_register_sql_injection_rejected(self, client_no_override): + """Registration endpoint should reject SQL injection payloads.""" + payloads = [ + "' OR '1'='1", + "admin'--; DROP TABLE users;--", + "1' UNION SELECT * FROM users--", + ] + for payload in payloads: + response = await client_no_override.post( + "/api/v1/auth/register", + json={"email": payload, "password": "password123", "name": "test"}, + ) + # 429 is acceptable — rate-limited is a valid security response + assert response.status_code in (400, 422, 429), ( + f"SQL injection payload '{payload}' returned {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_query_path_param_injection(self, async_client, auth_headers): + """Path parameters should not be vulnerable to SQL injection. + + UUID-type path parameters will fail validation for non-UUID inputs. + """ + injection_payloads = [ + "1' OR '1'='1", + "1; DROP TABLE queries; --", + "' UNION SELECT * FROM users--", + ] + for payload in injection_payloads: + response = await async_client.get( + f"/api/v1/queries/{payload}", + headers=auth_headers, + ) + # Non-UUID path params should return 422 (validation error) + assert response.status_code in (404, 422), ( + f"Path param injection '{payload}' returned {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_brand_path_param_injection(self, async_client, auth_headers): + """Brand path parameters should reject SQL injection.""" + injection_payloads = [ + "1' OR '1'='1", + "1; DROP TABLE brands; --", + ] + for payload in injection_payloads: + response = await async_client.get( + f"/api/v1/brands/{payload}/", + headers=auth_headers, + ) + assert response.status_code in (404, 422), ( + f"Brand path param injection '{payload}' returned {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_forgot_password_sql_injection_rejected(self, client_no_override): + """Forgot-password endpoint should reject SQL injection payloads.""" + payloads = [ + "' OR '1'='1", + "admin'--", + ] + for payload in payloads: + response = await client_no_override.post( + "/api/v1/auth/forgot-password", + json={"email": payload}, + ) + assert response.status_code in (200, 422, 429), ( + f"SQL injection payload '{payload}' returned {response.status_code}" + ) + # Even if 200 (generic response), should not leak user existence + if response.status_code == 200: + data = response.json() + assert "message" in data + + @pytest.mark.asyncio + async def test_reset_password_sql_injection_rejected(self, client_no_override): + """Reset-password endpoint should handle injection payloads safely.""" + response = await client_no_override.post( + "/api/v1/auth/reset-password", + json={ + "token": "' OR '1'='1", + "new_password": "newpassword123", + }, + ) + # Token should be rejected (invalid or expired), not cause SQL error + assert response.status_code in (400, 422, 429), ( + f"Reset password injection returned {response.status_code}" + ) + + +# ═══════════════════════════════════════════════════════════ +# XSS Protection Tests +# ═══════════════════════════════════════════════════════════ + + +class TestXSSProtection: + """Verify that XSS attack vectors are properly mitigated. + + For a pure JSON API, XSS payloads stored as-is in the database is + expected behavior — JSON responses are not rendered as HTML by + browsers. The real XSS protections are: + 1. Content-Type: application/json (prevents HTML rendering) + 2. Security headers (X-XSS-Protection, X-Content-Type-Options, etc.) + 3. Frontend escaping when rendering data in HTML + """ + + @pytest.mark.asyncio + async def test_api_returns_json_content_type(self, async_client, auth_headers): + """All API responses must have Content-Type: application/json. + + This is the primary XSS defense for JSON APIs — browsers will + not execute scripts in JSON responses. + """ + endpoints = [ + ("/api/v1/brands/", "GET"), + ("/api/v1/queries/", "GET"), + ] + for path, method in endpoints: + response = await async_client.get(path, headers=auth_headers) + if response.status_code == 200: + content_type = response.headers.get("content-type", "") + assert "application/json" in content_type, ( + f"Response for {path} has Content-Type '{content_type}', " + f"expected 'application/json'" + ) + + @pytest.mark.asyncio + async def test_brand_name_xss_not_executable(self, async_client, auth_headers): + """XSS payloads in brand name should be stored as plain text. + + In a JSON API, script tags are stored as text and not executed + because the response Content-Type is application/json. + The key assertion is that the response is valid JSON (not HTML). + """ + xss_payloads = [ + "", + "", + "javascript:alert(1)", + "", + "", + ] + for payload in xss_payloads: + response = await async_client.put( + f"/api/v1/brands/{brand.id}/", + json={"aliases": [payload]}, + headers=auth_headers, + ) + if response.status_code == 200: + data = response.json() + content_type = response.headers.get("content-type", "") + assert "application/json" in content_type + # XSS payloads stored as plain text in JSON + assert payload in data.get("aliases", []) + + @pytest.mark.asyncio + async def test_query_keyword_xss_as_plain_text(self, async_client, auth_headers): + """XSS payloads in query keyword should be stored as plain text.""" + xss_payload = "" + response = await async_client.post( + "/api/v1/queries/", + json={ + "keyword": xss_payload, + "target_brand": "Test Brand", + "platforms": ["wenxin"], + }, + headers=auth_headers, + ) + if response.status_code in (200, 201): + data = response.json() + content_type = response.headers.get("content-type", "") + assert "application/json" in content_type + # XSS payload stored as plain text + assert data.get("keyword") == xss_payload + + @pytest.mark.asyncio + async def test_security_headers_present(self, async_client): + """Verify that security response headers are set on all responses.""" + response = await async_client.get("/health") + assert response.status_code == 200 + + # Check essential security headers + assert response.headers.get("x-content-type-options") == "nosniff", ( + "X-Content-Type-Options header missing or incorrect" + ) + assert response.headers.get("x-frame-options") == "DENY", ( + "X-Frame-Options header missing or incorrect" + ) + assert response.headers.get("x-xss-protection") == "1; mode=block", ( + "X-XSS-Protection header missing or incorrect" + ) + assert response.headers.get("referrer-policy") == "strict-origin-when-cross-origin", ( + "Referrer-Policy header missing or incorrect" + ) + + @pytest.mark.asyncio + async def test_security_headers_on_api_endpoints(self, async_client, auth_headers): + """Security headers should be present on API endpoints too.""" + response = await async_client.get("/api/v1/brands/", headers=auth_headers) + if response.status_code == 200: + assert response.headers.get("x-content-type-options") == "nosniff" + assert response.headers.get("x-frame-options") == "DENY" + assert response.headers.get("x-xss-protection") == "1; mode=block" + + +# ═══════════════════════════════════════════════════════════ +# Authentication Security Tests +# ═══════════════════════════════════════════════════════════ + + +class TestAuthSecurity: + """Verify authentication security mechanisms.""" + + @pytest.mark.asyncio + async def test_expired_token_rejected(self, client_no_override): + """Expired JWT tokens should be rejected with 401.""" + # Create a token that expired 1 hour ago + expired_payload = { + "sub": str(uuid.uuid4()), + "exp": datetime.utcnow() - timedelta(hours=1), + "type": "access", + } + expired_token = jwt.encode(expired_payload, settings.JWT_SECRET, algorithm="HS256") + + response = await client_no_override.get( + "/api/v1/auth/me", + headers={"Authorization": f"Bearer {expired_token}"}, + ) + assert response.status_code == 401, ( + f"Expired token should be rejected, got {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_invalid_token_rejected(self, client_no_override): + """Invalid JWT tokens should be rejected with 401.""" + invalid_tokens = [ + "invalid.token.here", + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.invalid.payload", + "null", + "undefined", + ] + for token in invalid_tokens: + response = await client_no_override.get( + "/api/v1/auth/me", + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 401, ( + f"Invalid token '{token[:20]}...' should be rejected, got {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_invalid_refresh_token(self, client_no_override): + """Invalid refresh tokens should return 401.""" + invalid_tokens = [ + "invalid.refresh.token", + "eyJhbGciOiJIUzI1NiJ9.invalid.payload", + ] + for token in invalid_tokens: + response = await client_no_override.post( + "/api/v1/auth/refresh", + json={"refresh_token": token}, + ) + assert response.status_code == 401, ( + f"Invalid refresh token should be rejected, got {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_access_token_used_as_refresh_rejected(self, client_no_override, test_user): + """Access tokens should not be accepted as refresh tokens.""" + access_token = create_access_token(data={"sub": str(test_user.id)}) + + response = await client_no_override.post( + "/api/v1/auth/refresh", + json={"refresh_token": access_token}, + ) + assert response.status_code == 401, ( + "Access token used as refresh token should be rejected" + ) + + @pytest.mark.asyncio + async def test_refresh_token_used_as_access_rejected(self, client_no_override, test_user): + """Refresh tokens should not be accepted as access tokens.""" + refresh_token = create_refresh_token(data={"sub": str(test_user.id)}) + + response = await client_no_override.get( + "/api/v1/auth/me", + headers={"Authorization": f"Bearer {refresh_token}"}, + ) + assert response.status_code == 401, ( + "Refresh token used as access token should be rejected" + ) + + @pytest.mark.asyncio + async def test_missing_authorization_header(self, client_no_override): + """Requests without Authorization header should return 401.""" + response = await client_no_override.get("/api/v1/auth/me") + assert response.status_code in (401, 403), ( + f"Missing auth should return 401/403, got {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_cross_user_data_isolation( + self, async_session, test_user, second_user, auth_headers + ): + """User A should not be able to access User B's brand data.""" + # Create a brand for second_user + brand = Brand( + id=uuid.uuid4(), + user_id=second_user.id, + name="Second User's Brand", + platforms=["wenxin"], + status="active", + ) + async_session.add(brand) + await async_session.commit() + await async_session.refresh(brand) + + async def override_get_db(): + yield async_session + + app.dependency_overrides[get_db] = override_get_db + # Do NOT override get_current_user — let JWT auth work naturally + + test_user_token = create_access_token(data={"sub": str(test_user.id)}) + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + # test_user tries to access second_user's brand + response = await client.get( + f"/api/v1/brands/{brand.id}/", + headers={"Authorization": f"Bearer {test_user_token}"}, + ) + assert response.status_code == 404, ( + f"User should not access another user's brand, got {response.status_code}" + ) + + app.dependency_overrides.clear() + + @pytest.mark.asyncio + async def test_cross_user_query_isolation( + self, async_session, test_user, second_user + ): + """User A should not be able to access User B's query data.""" + query = Query( + id=uuid.uuid4(), + user_id=second_user.id, + keyword="Second User Query", + target_brand="Second Brand", + platforms=["wenxin"], + status="active", + ) + async_session.add(query) + await async_session.commit() + await async_session.refresh(query) + + async def override_get_db(): + yield async_session + + app.dependency_overrides[get_db] = override_get_db + + test_user_token = create_access_token(data={"sub": str(test_user.id)}) + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + response = await client.get( + f"/api/v1/queries/{query.id}", + headers={"Authorization": f"Bearer {test_user_token}"}, + ) + assert response.status_code == 404, ( + f"User should not access another user's query, got {response.status_code}" + ) + + app.dependency_overrides.clear() + + @pytest.mark.asyncio + async def test_nonexistent_user_token_rejected(self, client_no_override): + """Token with nonexistent user_id should be rejected.""" + fake_user_id = str(uuid.uuid4()) + token = create_access_token(data={"sub": fake_user_id}) + + response = await client_no_override.get( + "/api/v1/auth/me", + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 401, ( + f"Token for nonexistent user should be rejected, got {response.status_code}" + ) + + @pytest.mark.asyncio + async def test_login_error_message_no_user_enumeration(self, client_no_override): + """Login error messages should not reveal whether email exists. + + Both non-existent email and wrong password should return + the same error status. Rate limiting (429) is also acceptable. + """ + # Non-existent email + response1 = await client_no_override.post( + "/api/v1/auth/login", + json={"email": "nonexistent@example.com", "password": "password123"}, + ) + + # Existing email with wrong password + response2 = await client_no_override.post( + "/api/v1/auth/login", + json={"email": "security_test@example.com", "password": "WrongPassword999!"}, + ) + + # Both should return the same status code (either 401 or 429 if rate-limited) + # The key point: no information leakage about whether the user exists + assert response1.status_code in (401, 429), ( + f"Non-existent email login returned {response1.status_code}, expected 401/429" + ) + assert response2.status_code in (401, 429), ( + f"Wrong password login returned {response2.status_code}, expected 401/429" + ) + + # When both return 401 (not rate-limited), verify same error structure + if response1.status_code == 401 and response2.status_code == 401: + # Both should have consistent error responses (no user enumeration) + assert response1.status_code == response2.status_code diff --git a/backend/update_email.py b/backend/update_email.py deleted file mode 100644 index 4602111..0000000 --- a/backend/update_email.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Update admin email from admin@ficher.com to admin@fischer.com""" -import asyncio -import sys -sys.path.insert(0, '/Users/Chiguyong/Code/GEO/backend') - -from sqlalchemy import text -from app.database import AsyncSessionLocal - -async def main(): - async with AsyncSessionLocal() as session: - # Check current user - result = await session.execute(text("SELECT id, email FROM users WHERE email='admin@ficher.com'")) - row = result.fetchone() - if row: - print(f"Found user: id={row[0]}, email={row[1]}") - await session.execute(text("UPDATE users SET email='admin@fischer.com' WHERE email='admin@ficher.com'")) - await session.commit() - print("Email updated to admin@fischer.com") - else: - print("No user found with admin@ficher.com") - result2 = await session.execute(text("SELECT id, email FROM users WHERE email='admin@fischer.com'")) - row2 = result2.fetchone() - if row2: - print(f"Already updated: id={row2[0]}, email={row2[1]}") - else: - print("No admin user found at all!") - all_users = await session.execute(text("SELECT id, email FROM users LIMIT 10")) - for u in all_users.fetchall(): - print(f" User: id={u[0]}, email={u[1]}") - - # Verify - verify = await session.execute(text("SELECT id, email FROM users WHERE email='admin@fischer.com'")) - v = verify.fetchone() - if v: - print(f"Verified: id={v[0]}, email={v[1]}") - else: - print("WARNING: Verification failed - admin@fischer.com not found!") - -asyncio.run(main()) diff --git a/csrf.json b/csrf.json new file mode 100644 index 0000000..96602e2 --- /dev/null +++ b/csrf.json @@ -0,0 +1 @@ +{"csrfToken":"defd4951c4d87238088193a161570b32ea50fa5015753e6e6eeb4adc1d7c0f8c"} \ No newline at end of file diff --git a/csrf_headers.txt b/csrf_headers.txt new file mode 100644 index 0000000..f547534 --- /dev/null +++ b/csrf_headers.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch +cache-control: private, no-cache, no-store +content-type: application/json +expires: 0 +pragma: no-cache +set-cookie: next-auth.csrf-token=8ecba5438bf185bf0a664e52de0510a57ded93697162fbcf4d61435397cba604%7C6d4116c237ade107969662e104cfd7ab4580ea3306b948a5842c27202943ef5d; Path=/; HttpOnly; SameSite=Lax +set-cookie: next-auth.callback-url=http%3A%2F%2Flocalhost%3A3000; Path=/; HttpOnly; SameSite=Lax +Date: Sat, 23 May 2026 08:44:02 GMT +Connection: keep-alive +Keep-Alive: timeout=5 +Transfer-Encoding: chunked + diff --git a/csrf_resp.json b/csrf_resp.json new file mode 100644 index 0000000..193cfd1 --- /dev/null +++ b/csrf_resp.json @@ -0,0 +1 @@ +{"csrfToken":"8ecba5438bf185bf0a664e52de0510a57ded93697162fbcf4d61435397cba604"} \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..1d9c806 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,140 @@ +# ============================================================ +# GEO Platform — 生产环境 Docker Compose 配置 +# +# 生产部署前必须完成的配置: +# 1. 创建 .env.production 文件(参考 .env.example),配置真实密钥: +# - SECRET_KEY / NEXTAUTH_SECRET(使用随机强密码) +# - DATABASE_URL(建议使用托管数据库,如 RDS / Cloud SQL) +# - REDIS_URL(建议使用托管 Redis,如 ElastiCache) +# - LLM API Keys(DASHSCOPE_API_KEY 等) +# 2. 配置反向代理(Nginx / Caddy)并启用 HTTPS +# 3. 将数据库和 Redis 卷挂载到持久化存储(或使用托管服务) +# 4. 检查防火墙规则,生产环境不应暴露 5432 / 6379 端口到公网 +# 5. 使用 docker compose -f docker-compose.prod.yml up -d 启动 +# ============================================================ + +version: "3.9" + +services: + db: + image: postgres:15-alpine + container_name: geo_db_prod + restart: always + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB:-geo_platform} + # 生产环境不对外暴露数据库端口 + expose: + - "5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB:-geo_platform}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + deploy: + resources: + limits: + memory: 1g + cpus: '1.0' + reservations: + memory: 512m + networks: + - geo_internal + + redis: + image: redis:7-alpine + container_name: geo_redis_prod + restart: always + # 使用密码保护 Redis(生产必须配置) + command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 200mb --maxmemory-policy allkeys-lru + expose: + - "6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 15s + deploy: + resources: + limits: + memory: 256m + cpus: '0.5' + reservations: + memory: 128m + networks: + - geo_internal + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: geo_backend_prod + restart: always + expose: + - "8000" + env_file: + - .env.production + # 生产环境不挂载源代码目录,镜像内已包含完整代码 + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + # 使用 Dockerfile 中定义的 gunicorn 启动命令 + deploy: + resources: + limits: + memory: 1g + cpus: '2.0' + reservations: + memory: 512m + networks: + - geo_internal + - geo_public + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: geo_frontend_prod + restart: always + ports: + # 通过反向代理访问,本地仅绑定 127.0.0.1 + - "127.0.0.1:3000:3000" + env_file: + - .env.production + # 生产环境不挂载源代码目录 + depends_on: + - backend + deploy: + resources: + limits: + memory: 512m + cpus: '1.0' + reservations: + memory: 256m + networks: + - geo_internal + - geo_public + +volumes: + postgres_data: + driver: local + redis_data: + driver: local + +networks: + # 内部网络:服务间通信,不对外暴露 + geo_internal: + driver: bridge + internal: true + # 公共网络:frontend/backend 对外提供服务 + geo_public: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml index c1c9735..70de3ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,13 @@ services: interval: 5s timeout: 5s retries: 5 + deploy: + resources: + limits: + memory: 512m + cpus: '0.5' + reservations: + memory: 256m redis: image: redis:7-alpine @@ -32,6 +39,13 @@ services: interval: 5s timeout: 5s retries: 5 + deploy: + resources: + limits: + memory: 128m + cpus: '0.25' + reservations: + memory: 64m backend: build: ./backend @@ -49,6 +63,13 @@ services: redis: condition: service_healthy command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload + deploy: + resources: + limits: + memory: 512m + cpus: '1.0' + reservations: + memory: 256m frontend: build: ./frontend @@ -64,6 +85,13 @@ services: depends_on: - backend command: npm run dev + deploy: + resources: + limits: + memory: 256m + cpus: '0.5' + reservations: + memory: 128m volumes: postgres_data: diff --git a/docs/后续待办事项.md b/docs/后续待办事项.md new file mode 100644 index 0000000..6d40599 --- /dev/null +++ b/docs/后续待办事项.md @@ -0,0 +1,116 @@ +# GEO 平台后续待办事项 + +## 优先级说明 +- 🔴 P0:阻断核心业务,必须立即处理 +- 🟠 P1:影响用户体验,本周内解决 +- 🟡 P2:功能增强,下一迭代安排 +- 🟢 P3:锦上添花,有空再做 + +--- + +## 🟠 P1 - 本周优先 + +### 1. 数据库迁移同步 +- [ ] 为 onboarding API 中可能缺少的字段创建 Alembic 迁移 +- [ ] 检查 brands/competitors 表结构是否完整匹配当前 API 需求 +- [ ] 运行 `alembic revision --autogenerate` 确认无漂移 + +### 2. 多 AI 平台真实对接验证 +- [ ] 验证文心一言平台适配器能否正常工作 +- [ ] 验证 Kimi(月之暗面)平台适配器能否正常工作(`MOONSHOT_API_KEY`) +- [ ] 验证通义千问平台适配器能否正常工作(`TONGYI_API_KEY`) +- [ ] 验证百度千帆平台适配器能否正常工作(`BAIDU_QIANFAN_API_KEY`) +- [ ] 验证豆包(字节跳动)平台适配器能否正常工作(`DOUBAO_API_KEY`) +- [ ] 配置各平台所需的 API Key 到 .env + +### 3. 定时调度器验证 +- [ ] 确认 APScheduler 定时任务是否正常触发 +- [ ] 验证每日/每周查询自动执行 +- [ ] 测试调度器重启后任务恢复 + +--- + +## 🟡 P2 - 下一迭代 + +### 4. Agent 架构完善 +- [ ] Legacy Worker 迁移到 Agent 框架 +- [ ] Pipeline YAML 编排引擎增强(条件分支、循环) +- [ ] Agent 监控 Dashboard(执行状态、耗时、成功率) +- [ ] 新增内容审核 Agent + +### 5. 内容生产完整链路 +- [ ] 完善 AI 内容生成质量(Prompt 优化) +- [ ] 实现内容审核流程(人工 + AI 双审) +- [ ] 多平台发布管理(知乎、百家号、头条等) +- [ ] 发布后效果归因(发布 → 引用率变化关联) +- [ ] 将 MockEmbedder 替换为 OpenAIEmbedder(生产环境) + +### 6. 平台规则审查 +- [ ] 建立各 AI 平台收录规则库 +- [ ] 内容合规性自动检查 +- [ ] SEO/GEO 最佳实践建议引擎 + +### 7. 数据分析增强 +- [ ] 品牌健康分趋势预测 +- [ ] 竞品动态预警(某竞品引用率突增) +- [ ] 行业基准对比 +- [ ] 自定义报告模板 + +--- + +## 🟢 P3 - 长期规划 + +### 8. 多租户与商业化 +- [ ] 订阅套餐计费实现(免费/Pro/Enterprise) +- [ ] 多组织/团队协作 +- [ ] 使用量配额与计费 +- [ ] 发票与支付集成 + +### 9. 性能与可扩展性 +- [ ] 引用检测任务队列(Celery/RQ)替代内存调度 +- [ ] 数据库读写分离 +- [ ] CDN 静态资源加速 +- [ ] WebSocket 实时通知 + +### 10. 运维与部署 +- [ ] K8s 部署配置 +- [ ] CI/CD 中 README 的 GitHub 用户名替换 +- [ ] Sentry 错误监控接入(ErrorBoundary 已预留) +- [ ] Grafana + Prometheus 监控大盘 +- [ ] 自动化备份策略 + +### 11. 用户体验 +- [ ] 邮件通知系统(监测报告推送) +- [ ] 移动端适配 +- [ ] 国际化(i18n) +- [ ] 用户引导优化(交互式教程) + +--- + +## 已完成项目 ✅ + +- [x] JWT 认证 + NextAuth 集成(Access Token + Refresh Token 滑动过期) +- [x] 品牌/竞品/查询 CRUD +- [x] 引用检测(百炼 qwen3-coder-plus 真实调用) +- [x] Onboarding 引导流程(前后端完整对接) +- [x] 知识库 RAG 对接(MockEmbedder + RAGService) +- [x] 内容管理 + RAG 知识库检索 + 版本管理 +- [x] 内容生产 Pipeline(生成→去AI化→GEO优化) +- [x] 多用户数据隔离修复 +- [x] Agent 并发控制(Semaphore) +- [x] LLM 令牌桶限流 +- [x] 前端 SWR + Zustand 状态管理 +- [x] 结构化日志 + RequestID + 性能监控 +- [x] 安全测试 + 前端测试体系 +- [x] GitHub Actions CI/CD +- [x] 健康检查 /health + /ready +- [x] 告警通知系统(告警列表 + 告警设置 + 未读计数) +- [x] 内容分发管理(平台规则 + 格式化 + 发布排期) +- [x] 监测优化 Analytics(发布记录 + 效果指标 + AI 洞察) +- [x] 客户管理(Organization 映射) +- [x] 生命周期项目管理(5 阶段 + 时间线) +- [x] 订阅管理(套餐/订阅/取消/历史) +- [x] 管理员后台(用户管理 + 套餐管理 + 系统统计) +- [x] 多 LLM Provider 支持(OpenAI 兼容 + DeepSeek) +- [x] Redis 缓存层(品牌列表 + 仪表盘 + 用户 Profile) +- [x] 安全响应头(X-Content-Type-Options / X-Frame-Options / X-XSS-Protection) diff --git a/docs/操作流程.md b/docs/操作流程.md new file mode 100644 index 0000000..86e32ad --- /dev/null +++ b/docs/操作流程.md @@ -0,0 +1,399 @@ +# GEO 平台操作流程 + +## 一、环境准备 + +### 1.1 系统要求 +- Node.js 18+ +- Python 3.11+ +- PostgreSQL 15 +- Redis 7 +- Docker & Docker Compose(推荐) + +### 1.2 环境变量配置 + +在项目根目录 `.env` 文件中配置以下关键项: + +| 变量名 | 示例值 | 说明 | +|--------|--------|------| +| `DATABASE_URL` | `postgresql+asyncpg://chiguyong@localhost:5432/geo_platform` | PostgreSQL 异步连接串 | +| `REDIS_URL` | `redis://localhost:6379/0` | Redis 连接串 | +| `JWT_SECRET` | `a3f8c2e1d7b9...` | JWT 签名密钥,**必须 ≥ 32 字符**,否则启动失败 | +| `JWT_EXPIRE_HOURS` | `24` | JWT Access Token 过期时间(小时) | +| `NEXT_PUBLIC_API_URL` | `http://localhost:8000` | 前端调用后端的 API 地址 | +| `CORS_ORIGINS` | `http://localhost:3000,http://localhost:3001` | 允许跨域的前端地址 | +| `ENABLE_LLM` | `true` | 启用真实 AI 引用检测(`false` 则使用 Mock) | +| `OPENAI_API_KEY` | `sk-sp-c76f198d...` | 百炼 DashScope API 密钥 | +| `OPENAI_BASE_URL` | `https://coding.dashscope.aliyuncs.com/v1` | 百炼 DashScope 端点(OpenAI 兼容格式) | +| `DEFAULT_LLM_PROVIDER` | `openai` | LLM 提供商(`openai` / `deepseek`) | +| `LLM_MODEL` | `qwen3-coder-plus` | 默认调用模型名 | +| `ZHIPU_API_KEY` | _(可选)_ | 智谱 AI API Key | +| `TONGYI_API_KEY` | _(可选)_ | 通义千问 API Key | +| `MOONSHOT_API_KEY` | _(可选)_ | Kimi(月之暗面)API Key | +| `BAIDU_QIANFAN_API_KEY` | _(可选)_ | 百度千帆 API Key | +| `DOUBAO_API_KEY` | _(可选)_ | 豆包(字节跳动)API Key | +| `API_RATE_LIMIT_RPM` | `10` | AI 平台 API 调用频率限制(每分钟请求数) | + +> **提示**:`JWT_SECRET` 启动时会强制校验长度,不足 32 字符将直接退出进程。可用以下命令生成: +> ```bash +> python3 -c "import secrets; print(secrets.token_hex(32))" +> ``` + +--- + +## 二、系统启动 + +### 2.1 Docker 一键启动(推荐) + +```bash +docker-compose up -d +``` + +启动后访问: +- 前端:http://localhost:3000 +- 后端 API:http://localhost:8000 +- API 文档(Swagger):http://localhost:8000/docs + +Docker Compose 编排四个服务: + +| 服务 | 镜像 | 端口 | 依赖 | +|------|------|------|------| +| `db` | postgres:15-alpine | 5432 | — | +| `redis` | redis:7-alpine | 6379 | — | +| `backend` | 自建(./backend) | 8000 | db + redis 健康检查 | +| `frontend` | 自建(./frontend) | 3000 | backend | + +数据持久化卷:`postgres_data`、`redis_data` + +### 2.2 本地开发启动 + +后端: +```bash +cd backend +pip install -r requirements.txt +alembic upgrade head +uvicorn app.main:app --reload --port 8000 +``` + +前端: +```bash +cd frontend +npm install +npm run dev +``` + +> **注意**:生产环境启动后端应使用 `--no-reload` 参数,避免文件监视导致的进程崩溃。 + +--- + +## 三、业务操作流程 + +### 3.1 用户注册与登录 +- 测试账号:`admin@fischer.com` / `Admin@123` +- 注册流程:`POST /api/v1/auth/register` → 邮箱验证 → 登录 +- 登录流程:`POST /api/v1/auth/login` → 获取 Access Token + Refresh Token + +### 3.2 Onboarding 引导(新用户首次登录) +1. 创建品牌(填写品牌名称、行业)→ `POST /api/v1/onboarding/brand` +2. 选择竞品(系统自动推荐 + 手动添加)→ `GET /api/v1/onboarding/competitor-recommendations` +3. 查看品牌健康报告(AI 分析品牌在各平台的表现)→ `GET /api/v1/onboarding/health-report/{brand_id}` +4. 获取行动建议(基于数据的优化建议)→ `GET /api/v1/onboarding/action-suggestions/{brand_id}` +5. 完成引导 → `POST /api/v1/onboarding/complete/{brand_id}` → 进入仪表盘 + +### 3.3 品牌管理 +- 创建/编辑/删除品牌(`/api/v1/brands/`) +- 管理品牌下的竞品(`/api/v1/brands/{brand_id}/competitors/`) +- 查看品牌评分(`/api/v1/brands/{brand_id}/score/`、`/api/v1/brands/{brand_id}/score/history/`) +- 配置品牌别名(用于多名称匹配) + +### 3.4 查询管理 +- 创建监测查询词(如"XXX品牌怎么样")→ `POST /api/v1/queries/` +- 查看查询列表 → `GET /api/v1/queries/` +- 立即执行检测 → `POST /api/v1/queries/{query_id}/run-now` +- 设置查询频率(即时/每日/每周),由 APScheduler 定时调度自动执行 + +### 3.5 引用检测 +- 系统自动调用 AI 平台检测品牌引用 +- 使用百炼 `qwen3-coder-plus` 模型分析引用情况 +- 记录:是否被引用、引用位置、情感倾向、置信度 +- 查看引用列表 → `GET /api/v1/citations/` +- 查看引用统计 → `GET /api/v1/citations/stats` + +### 3.6 数据分析与报告 +- 仪表盘统计:`GET /api/v1/dashboard/stats` + - 综合评分(V2)、健康等级、较昨日变化 + - 五维度评分详情(提及率、推荐排名、情感评分、引用质量、竞争地位) + - 各平台评分对比(含竞品) +- 报告导出:`GET /api/v1/reports/export/csv`、`GET /api/v1/reports/export/pdf` +- 引用详情查看与筛选 + +### 3.7 内容管理 +- 内容 CRUD:`/api/v1/contents/`(列表、创建、查看、更新、删除、发布) +- AI 内容生成:`POST /api/v1/content/generate` + - 流程:内容生成 → 去AI化 → GEO优化(三阶段 Pipeline) + - 支持知识库 RAG 上下文增强 +- AI 选题生成:`POST /api/v1/content/generate-topics` +- 品牌知识库条目:`/api/v1/contents/knowledge/`(CRUD) + +### 3.8 知识库 +- 创建/列出/查看/删除知识库 → `/api/v1/knowledge/bases` +- 上传文档到知识库 → `POST /api/v1/knowledge/bases/{kb_id}/documents` + - 支持 text / markdown / url 三种来源 + - 自动分块 + 向量化(MockEmbedder / OpenAIEmbedder) +- 文档管理(列出/删除)→ `/api/v1/knowledge/bases/{kb_id}/documents` +- 查看文档分块 → `GET /api/v1/knowledge/bases/{kb_id}/documents/{doc_id}/chunks` +- RAG 检索 → `POST /api/v1/knowledge/search` + +### 3.9 内容分发 +- 获取支持平台列表 → `GET /api/v1/distribution/platforms` +- 内容合规校验 → `POST /api/v1/distribution/validate` +- 生成发布策略 → `POST /api/v1/distribution/strategy` +- 内容格式化 → `POST /api/v1/distribution/format` +- 创建发布排期 → `POST /api/v1/distribution/schedule` + +### 3.10 监测优化(Analytics) +- 记录发布 → `POST /api/v1/analytics/publish` +- 更新效果指标 → `PUT /api/v1/analytics/metrics/{publish_id}` +- 全局概览 → `GET /api/v1/analytics/overview` +- 单内容详情 → `GET /api/v1/analytics/content/{publish_id}` +- 排行榜 → `GET /api/v1/analytics/top` +- 洞察列表 → `GET /api/v1/analytics/insights` +- AI 生成洞察 → `POST /api/v1/analytics/insights/generate` +- 标记洞察已应用 → `POST /api/v1/analytics/insights/{insight_id}/apply` + +### 3.11 告警通知 +- 查看告警列表 → `GET /api/v1/alerts/` +- 未读告警数 → `GET /api/v1/alerts/unread-count` +- 全部标为已读 → `PATCH /api/v1/alerts/read-all` +- 单条标为已读 → `PATCH /api/v1/alerts/{alert_id}/read` +- 告警设置管理 → `/api/v1/alerts/settings` + +### 3.12 客户管理 +- 客户(组织)CRUD → `/api/v1/clients/` +- 查看客户下项目 → `GET /api/v1/clients/{client_id}/projects` + +### 3.13 生命周期项目管理 +- 项目列表 → `GET /api/v1/lifecycle/projects/` +- 项目统计 → `GET /api/v1/lifecycle/projects/stats` +- 快速创建项目 → `POST /api/v1/lifecycle/projects/quick-start` +- 项目时间线 → `GET /api/v1/lifecycle/projects/{project_id}/timeline` +- 阶段管理 → `/api/v1/lifecycle/projects/{project_id}/stages` + +### 3.14 Agent 管理 +- 列出所有 Agent → `GET /api/v1/agents/` +- Agent 详情/配置 → `/api/v1/agents/{agent_name}` +- 任务管理 → `/api/v1/agents/tasks/`(创建、查询状态、取消、日志) + +### 3.15 订阅管理 +- 查看套餐 → `GET /api/v1/subscriptions/plans` +- 当前订阅 → `GET /api/v1/subscriptions/current` +- 订阅 → `POST /api/v1/subscriptions/subscribe` +- 取消订阅 → `POST /api/v1/subscriptions/cancel` +- 订阅历史 → `GET /api/v1/subscriptions/history` + +--- + +## 四、API 接口总览 + +### 认证 `/api/v1/auth` +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/register` | 用户注册 | +| POST | `/login` | 用户登录(返回 Access + Refresh Token) | +| POST | `/refresh` | 刷新 Token(滑动过期) | +| GET | `/me` | 获取当前用户信息 | +| POST | `/forgot-password` | 忘记密码(发送重置链接) | +| POST | `/reset-password` | 重置密码 | +| POST | `/verify-email` | 验证邮箱 | +| POST | `/resend-verification` | 重发验证码 | +| PUT | `/change-password` | 修改密码 | +| PUT | `/profile` | 更新个人资料 | + +### 品牌管理 `/api/v1/brands` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 获取当前用户所有品牌 | +| POST | `/` | 创建品牌 | +| GET | `/{brand_id}/` | 获取品牌详情 | +| PUT | `/{brand_id}/` | 更新品牌 | +| DELETE | `/{brand_id}/` | 删除品牌 | +| GET | `/{brand_id}/score/` | 获取品牌评分 | +| GET | `/{brand_id}/score/history/` | 获取评分历史 | +| * | `/{brand_id}/competitors/...` | 竞品管理(子路由) | + +### 查询词 `/api/v1/queries` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 查询词列表(分页) | +| POST | `/` | 创建查询词 | +| GET | `/{query_id}` | 查询词详情 | +| PUT | `/{query_id}` | 更新查询词 | +| DELETE | `/{query_id}` | 删除查询词 | +| POST | `/{query_id}/run-now` | 立即执行检测 | + +### 引用数据 `/api/v1/citations` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 引用列表(支持按 query_id/platform/日期筛选) | +| GET | `/stats` | 引用统计 | + +### 报告 `/api/v1/reports` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/export/csv` | 导出 CSV 报告 | +| GET | `/export/pdf` | 导出 PDF 报告 | + +### Onboarding `/api/v1/onboarding` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/status` | 检查 Onboarding 状态 | +| POST | `/brand` | 创建品牌(简化版) | +| GET | `/competitor-recommendations` | 竞品推荐 | +| GET | `/health-report/{brand_id}` | 品牌健康报告 | +| GET | `/action-suggestions/{brand_id}` | 行动建议 | +| POST | `/complete/{brand_id}` | 完成 Onboarding | + +### 内容生产 `/api/v1/content` +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/generate` | 一键生成内容(Pipeline:生成→去AI化→GEO优化) | +| POST | `/generate-topics` | AI 选题生成 | + +### 内容管理 `/api/v1/contents` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 内容列表(分页、筛选) | +| POST | `/` | 创建内容 | +| GET | `/{content_id}` | 内容详情 | +| PUT | `/{content_id}` | 更新内容 | +| DELETE | `/{content_id}` | 删除内容 | +| POST | `/{content_id}/publish` | 发布内容 | +| GET | `/knowledge/` | 品牌知识库条目列表 | +| POST | `/knowledge/` | 创建品牌知识库条目 | +| PUT | `/knowledge/{knowledge_id}` | 更新品牌知识库条目 | +| DELETE | `/knowledge/{knowledge_id}` | 删除品牌知识库条目 | + +### 知识库 `/api/v1/knowledge` +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/bases` | 创建知识库 | +| GET | `/bases` | 列出知识库 | +| GET | `/bases/{kb_id}` | 知识库详情 | +| DELETE | `/bases/{kb_id}` | 删除知识库 | +| POST | `/bases/{kb_id}/documents` | 上传文档 | +| GET | `/bases/{kb_id}/documents` | 列出文档 | +| DELETE | `/bases/{kb_id}/documents/{doc_id}` | 删除文档 | +| GET | `/bases/{kb_id}/documents/{doc_id}/chunks` | 查看文档分块 | +| POST | `/search` | RAG 语义检索 | + +### 仪表盘 `/api/v1/dashboard` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/stats` | 仪表盘统计(综合评分、维度、平台、竞品对比) | + +### 内容分发 `/api/v1/distribution` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/platforms` | 支持平台列表 | +| POST | `/validate` | 内容合规校验 | +| POST | `/strategy` | 生成发布策略 | +| POST | `/format` | 内容格式化 | +| POST | `/schedule` | 创建发布排期 | + +### 监测优化 `/api/v1/analytics` +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/publish` | 记录内容发布 | +| PUT | `/metrics/{publish_id}` | 更新效果指标 | +| GET | `/overview` | 全局效果概览 | +| GET | `/content/{publish_id}` | 单内容详细表现 | +| GET | `/top` | 表现最好内容排行 | +| GET | `/insights` | 洞察列表 | +| POST | `/insights/generate` | AI 生成洞察 | +| POST | `/insights/{insight_id}/apply` | 标记洞察已应用 | + +### 告警通知 `/api/v1/alerts` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 告警列表(支持类型/严重程度/已读状态/品牌筛选) | +| GET | `/unread-count` | 未读告警数 | +| PATCH | `/read-all` | 全部标为已读 | +| PATCH | `/{alert_id}/read` | 单条标为已读 | +| GET | `/settings` | 告警设置列表 | +| PUT | `/settings` | 批量更新告警设置 | +| PUT | `/settings/{setting_id}` | 更新单条告警设置 | + +### 客户管理 `/api/v1/clients` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 客户列表 | +| POST | `/` | 创建客户 | +| GET | `/{client_id}` | 客户详情 | +| PUT | `/{client_id}` | 更新客户 | +| DELETE | `/{client_id}` | 删除客户 | +| GET | `/{client_id}/projects` | 客户下的项目列表 | + +### 生命周期 `/api/v1/lifecycle` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/projects/` | 项目列表 | +| GET | `/projects/stats` | 项目统计 | +| POST | `/projects/quick-start` | 快速创建项目 | +| GET | `/projects/{project_id}/timeline` | 项目时间线 | +| GET | `/projects/{project_id}/stages` | 项目阶段列表 | +| PUT | `/projects/{project_id}/stages/{stage_number}` | 更新阶段状态 | + +### Agent 管理 `/api/v1/agents` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/` | 列出所有 Agent | +| GET | `/{agent_name}` | Agent 详情 | +| GET | `/{agent_name}/config` | Agent 配置 | +| PUT | `/{agent_name}/config` | 更新 Agent 配置 | +| GET | `/tasks/` | 任务列表 | +| POST | `/tasks/` | 创建任务(分发给 Agent) | +| GET | `/tasks/{task_id}` | 任务状态 | +| POST | `/tasks/{task_id}/cancel` | 取消任务 | +| GET | `/tasks/{task_id}/logs` | 任务日志 | + +### 订阅 `/api/v1/subscriptions` +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/plans` | 套餐列表 | +| GET | `/current` | 当前订阅 | +| POST | `/subscribe` | 订阅套餐 | +| POST | `/cancel` | 取消订阅 | +| GET | `/history` | 订阅历史 | + +### 管理员 `/api/v1/admin`(需管理员权限) +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/stats` | 系统统计 | +| GET | `/users` | 用户列表(分页、搜索) | +| GET | `/users/{user_id}` | 用户详情 | +| POST | `/users/{user_id}/toggle-active` | 启用/禁用用户 | +| PUT | `/users/{user_id}/update-plan` | 更新用户套餐 | + +--- + +## 五、监控与运维 + +### 5.1 健康检查 +- `GET /health` — 基础存活检查(Liveness),不依赖外部服务 +- `GET /ready` — 依赖就绪检查(Readiness),检测 DB + Redis 连通性 + - 返回 `200` + `{"status": "ready"}` 表示全部就绪 + - 返回 `503` + `{"status": "not_ready"}` 表示依赖异常 + +### 5.2 日志 +- 结构化 JSON 日志(`setup_logging()` 在启动时初始化) +- 每个请求附带 `X-Request-ID`(由 `RequestIdMiddleware` 注入) +- 慢请求(>1s)自动告警 +- 中间件执行链:RequestId → Metrics → RateLimit → RequestLogging → CORS → SecurityHeaders + +### 5.3 安全特性 +- JWT 认证 + 用户级数据隔离(所有查询均按 `current_user.id` 过滤) +- 用户+IP 组合限流(`RateLimitMiddleware`) +- Agent 并发控制(Semaphore) +- LLM 令牌桶限流(30 RPM) +- 安全响应头:`X-Content-Type-Options: nosniff`、`X-Frame-Options: DENY`、`X-XSS-Protection: 1; mode=block` +- 统一异常处理(不泄漏内部错误详情) +- 密码重置/邮箱验证等敏感操作防止用户枚举 diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..ecba89a --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,11 @@ +node_modules/ +.next/ +.env.local +.env.* +*.log +.git/ +.gitignore +README.md +test-results/ +playwright-report/ +e2e/ diff --git a/frontend/Dockerfile b/frontend/Dockerfile index e1c7a6c..85c054c 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,14 +1,45 @@ -FROM node:20-alpine +# ============================================================ +# Stage 1: Builder — 构建 Next.js 生产产物 +# ============================================================ +FROM node:20-alpine AS builder WORKDIR /app -# 安装依赖 +# 安装依赖(利用缓存层) COPY package.json package-lock.json ./ RUN npm ci -# 复制应用代码 +# 复制源码并构建 COPY . . +RUN npm run build + +# ============================================================ +# Stage 2: Runner — 只保留运行时必要文件 +# ============================================================ +FROM node:20-alpine AS runner + +WORKDIR /app + +ENV NODE_ENV=production + +# 创建非 root 用户运行应用 +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs + +# 复制 standalone 构建产物 +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/public ./public + +USER nextjs EXPOSE 3000 -CMD ["npm", "run", "dev"] +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ + CMD wget -qO- http://localhost:3000/ || exit 1 + +CMD ["node", "server.js"] diff --git a/frontend/__tests__/hooks/use-api.test.ts b/frontend/__tests__/hooks/use-api.test.ts new file mode 100644 index 0000000..e0a665f --- /dev/null +++ b/frontend/__tests__/hooks/use-api.test.ts @@ -0,0 +1,314 @@ +/** + * useApi / usePaginatedApi / useApiMutation Hooks 单元测试 + * + * 覆盖:加载/成功/错误状态、分页参数、mutation trigger + */ + +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { renderHook, act, waitFor } from "@testing-library/react"; +import useSWR from "swr"; +import { + useApi, + usePaginatedApi, + useApiMutation, + swrFetcher, +} from "@/lib/hooks/use-api"; +import type { PaginatedResponse } from "@/lib/hooks/use-api"; + +// ── Mock fetchWithAuth ──────────────────────────────────────────────────────── + +vi.mock("@/lib/api/client", () => ({ + fetchWithAuth: vi.fn(), +})); + +import { fetchWithAuth } from "@/lib/api/client"; +const mockFetchWithAuth = vi.mocked(fetchWithAuth); + +// ── swrFetcher ──────────────────────────────────────────────────────────────── + +describe("swrFetcher", () => { + it("应调用 fetchWithAuth 并返回结果", async () => { + mockFetchWithAuth.mockResolvedValueOnce({ data: "test" }); + + const result = await swrFetcher("/api/test"); + expect(result).toEqual({ data: "test" }); + expect(mockFetchWithAuth).toHaveBeenCalledWith("/api/test"); + }); +}); + +// ── useApi ──────────────────────────────────────────────────────────────────── + +describe("useApi", () => { + beforeEach(() => { + vi.clearAllMocks(); + // 清除 SWR 缓存,避免测试间数据残留 + useSWR.clearCache?.(); + }); + + it("url 为 null 时应暂停请求", () => { + const { result } = renderHook(() => useApi(null)); + + expect(result.current.isLoading).toBe(false); + expect(result.current.data).toBeUndefined(); + expect(mockFetchWithAuth).not.toHaveBeenCalled(); + }); + + it("请求成功应返回数据", async () => { + const mockData = { items: [{ id: "1", name: "品牌" }], total: 1 }; + mockFetchWithAuth.mockResolvedValueOnce(mockData); + + const { result } = renderHook(() => useApi("/api/brands-success")); + + await waitFor(() => { + expect(result.current.data).toEqual(mockData); + expect(result.current.error).toBeUndefined(); + expect(result.current.isLoading).toBe(false); + }); + }); + + it("请求失败应返回错误", async () => { + mockFetchWithAuth.mockRejectedValueOnce(new Error("网络错误")); + + const { result } = renderHook(() => useApi("/api/brands-error")); + + await waitFor(() => { + expect(result.current.error).toBeInstanceOf(Error); + expect(result.current.error?.message).toBe("网络错误"); + }); + }); + + it("refresh 应触发重新获取", async () => { + mockFetchWithAuth.mockResolvedValue({ items: [] }); + + const { result } = renderHook(() => useApi("/api/brands-refresh")); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + const callCount = mockFetchWithAuth.mock.calls.length; + act(() => { + result.current.refresh(); + }); + + await waitFor(() => { + expect(mockFetchWithAuth.mock.calls.length).toBeGreaterThan(callCount); + }); + }); +}); + +// ── usePaginatedApi ─────────────────────────────────────────────────────────── + +describe("usePaginatedApi", () => { + beforeEach(() => { + vi.clearAllMocks(); + useSWR.clearCache?.(); + }); + + it("应正确构造分页 URL", async () => { + const mockResponse: PaginatedResponse<{ id: string }> = { + items: [{ id: "1" }], + total: 10, + }; + mockFetchWithAuth.mockResolvedValueOnce(mockResponse); + + renderHook(() => + usePaginatedApi("/api/brands-page1", { page: 1, pageSize: 10 }) + ); + + await waitFor(() => { + // page=1, pageSize=10 → offset=0, limit=10 + expect(mockFetchWithAuth).toHaveBeenCalledWith( + "/api/brands-page1?limit=10&offset=0" + ); + }); + }); + + it("第2页应正确计算 offset", async () => { + const mockResponse: PaginatedResponse<{ id: string }> = { + items: [], + total: 20, + }; + mockFetchWithAuth.mockResolvedValueOnce(mockResponse); + + renderHook(() => + usePaginatedApi("/api/brands-page2", { page: 2, pageSize: 5 }) + ); + + await waitFor(() => { + // page=2, pageSize=5 → offset=5, limit=5 + expect(mockFetchWithAuth).toHaveBeenCalledWith( + "/api/brands-page2?limit=5&offset=5" + ); + }); + }); + + it("baseUrl 为 null 时应暂停请求", () => { + const { result } = renderHook(() => + usePaginatedApi(null, { page: 1, pageSize: 10 }) + ); + + expect(result.current.isLoading).toBe(false); + expect(result.current.data).toBeUndefined(); + }); + + it("应返回 total 和分页信息", async () => { + const mockResponse: PaginatedResponse<{ id: string }> = { + items: [{ id: "1" }, { id: "2" }], + total: 25, + }; + mockFetchWithAuth.mockResolvedValueOnce(mockResponse); + + const { result } = renderHook(() => + usePaginatedApi("/api/brands-total", { page: 1, pageSize: 10 }) + ); + + await waitFor(() => { + expect(result.current.data).toEqual([{ id: "1" }, { id: "2" }]); + expect(result.current.total).toBe(25); + expect(result.current.page).toBe(1); + expect(result.current.pageSize).toBe(10); + }); + }); + + it("setPage 应更新页码", async () => { + mockFetchWithAuth.mockResolvedValue({ + items: [], + total: 30, + }); + + const { result } = renderHook(() => + usePaginatedApi("/api/brands-setpage", { page: 1, pageSize: 10 }) + ); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + act(() => { + result.current.setPage(3); + }); + + await waitFor(() => { + expect(result.current.page).toBe(3); + }); + }); + + it("数据未加载时 total 应为 0", () => { + // 用 null URL 确保无请求发出,total 为 0 + const { result } = renderHook(() => + usePaginatedApi(null, { page: 1, pageSize: 10 }) + ); + + expect(result.current.total).toBe(0); + }); +}); + +// ── useApiMutation ──────────────────────────────────────────────────────────── + +describe("useApiMutation", () => { + beforeEach(() => { + vi.clearAllMocks(); + useSWR.clearCache?.(); + }); + + it("trigger 成功应返回数据", async () => { + const mockResult = { id: "1", name: "新品牌" }; + mockFetchWithAuth.mockResolvedValueOnce(mockResult); + + const { result } = renderHook(() => + useApiMutation("/api/brands", "POST") + ); + + let response: unknown; + await act(async () => { + response = await result.current.trigger({ name: "新品牌" }); + }); + + expect(response).toEqual(mockResult); + expect(result.current.isMutating).toBe(false); + expect(result.current.error).toBeUndefined(); + }); + + it("trigger 失败应返回 null 并设置 error", async () => { + mockFetchWithAuth.mockRejectedValueOnce(new Error("服务器错误")); + + const { result } = renderHook(() => + useApiMutation("/api/brands", "POST") + ); + + let response: unknown; + await act(async () => { + response = await result.current.trigger({ name: "失败" }); + }); + + expect(response).toBeNull(); + expect(result.current.error).toBeInstanceOf(Error); + expect(result.current.error?.message).toBe("服务器错误"); + expect(result.current.isMutating).toBe(false); + }); + + it("trigger 过程中 isMutating 应为 true", async () => { + let resolveMutation: (value: unknown) => void; + mockFetchWithAuth.mockReturnValueOnce( + new Promise((resolve) => { + resolveMutation = resolve; + }) + ); + + const { result } = renderHook(() => + useApiMutation("/api/brands", "PUT") + ); + + act(() => { + result.current.trigger({ name: "更新" }); + }); + + await waitFor(() => { + expect(result.current.isMutating).toBe(true); + }); + + resolveMutation!({ id: "1" }); + + await waitFor(() => { + expect(result.current.isMutating).toBe(false); + }); + }); + + it("reset 应清除错误状态", async () => { + mockFetchWithAuth.mockRejectedValueOnce(new Error("出错了")); + + const { result } = renderHook(() => + useApiMutation("/api/brands", "DELETE") + ); + + await act(async () => { + await result.current.trigger(); + }); + + expect(result.current.error).toBeDefined(); + + act(() => { + result.current.reset(); + }); + + expect(result.current.error).toBeUndefined(); + }); + + it("应正确传递 method 和 body", async () => { + mockFetchWithAuth.mockResolvedValueOnce({ success: true }); + + const { result } = renderHook(() => + useApiMutation("/api/brands/1", "PUT") + ); + + await act(async () => { + await result.current.trigger({ name: "更新品牌" }); + }); + + expect(mockFetchWithAuth).toHaveBeenCalledWith("/api/brands/1", { + method: "PUT", + body: JSON.stringify({ name: "更新品牌" }), + }); + }); +}); diff --git a/frontend/__tests__/lib/api/client.test.ts b/frontend/__tests__/lib/api/client.test.ts new file mode 100644 index 0000000..55d8fc0 --- /dev/null +++ b/frontend/__tests__/lib/api/client.test.ts @@ -0,0 +1,239 @@ +/** + * API Client (fetchWithAuth) 单元测试 + * + * 覆盖:带 token 请求、错误处理(401/500/204) + */ + +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { fetchWithAuth, API_BASE, getApiUrl } from "@/lib/api/client"; + +// ── Mock next-auth/react ────────────────────────────────────────────────────── + +vi.mock("next-auth/react", () => ({ + getSession: vi.fn(() => + Promise.resolve({ accessToken: "session-token-123" }) + ), +})); + +import { getSession } from "next-auth/react"; +const mockGetSession = vi.mocked(getSession); + +// ── Mock global fetch ───────────────────────────────────────────────────────── + +const mockFetch = vi.fn(); +const originalFetch = global.fetch; + +beforeEach(() => { + global.fetch = mockFetch; + vi.clearAllMocks(); +}); + +afterEach(() => { + global.fetch = originalFetch; +}); + +// ── 辅助 ────────────────────────────────────────────────────────────────────── + +function mockFetchResponse(options: { + ok: boolean; + status: number; + json?: () => Promise; +}) { + return { + ok: options.ok, + status: options.status, + json: options.json ?? (() => Promise.resolve({})), + }; +} + +// ── getApiUrl ───────────────────────────────────────────────────────────────── + +describe("getApiUrl", () => { + it("应拼接 API_BASE 和路径", () => { + const url = getApiUrl("/api/v1/brands"); + expect(url).toBe(`${API_BASE}/api/v1/brands`); + }); +}); + +// ── fetchWithAuth ───────────────────────────────────────────────────────────── + +describe("fetchWithAuth", () => { + it("显式传入 token 时应添加 Authorization 头", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 200, json: () => Promise.resolve({ data: "ok" }) }) + ); + + await fetchWithAuth("/api/test", {}, "my-secret-token"); + + const [url, options] = mockFetch.mock.calls[0]; + expect(url).toBe(`${API_BASE}/api/test`); + expect(options.headers.Authorization).toBe("Bearer my-secret-token"); + expect(options.headers["Content-Type"]).toBe("application/json"); + }); + + it("未传入 token 且在浏览器环境下应从 session 获取", async () => { + // 模拟浏览器环境 + const originalWindow = global.window; + Object.defineProperty(global, "window", { + value: { location: {} }, + writable: true, + }); + + mockGetSession.mockResolvedValueOnce({ + accessToken: "session-token-123", + }); + + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 200, json: () => Promise.resolve({ data: "ok" }) }) + ); + + await fetchWithAuth("/api/test", {}); + + const options = mockFetch.mock.calls[0][1]; + expect(options.headers.Authorization).toBe("Bearer session-token-123"); + + Object.defineProperty(global, "window", { + value: originalWindow, + writable: true, + }); + }); + + it("session 无 accessToken 时不应添加 Authorization 头", async () => { + // jsdom 环境下 typeof window !== "undefined",所以会走 session 路径 + mockGetSession.mockResolvedValueOnce({}); // session 没有 accessToken + + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 200, json: () => Promise.resolve({ data: "ok" }) }) + ); + + await fetchWithAuth("/api/test", {}); + + const options = mockFetch.mock.calls[0][1]; + expect(options.headers.Authorization).toBeUndefined(); + }); + + it("session 获取失败时不应添加 Authorization 头", async () => { + mockGetSession.mockRejectedValueOnce(new Error("session error")); + + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 200, json: () => Promise.resolve({ data: "ok" }) }) + ); + + await fetchWithAuth("/api/test", {}); + + const options = mockFetch.mock.calls[0][1]; + expect(options.headers.Authorization).toBeUndefined(); + }); + + it("应合并自定义 headers", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 200, json: () => Promise.resolve({}) }) + ); + + await fetchWithAuth("/api/test", { + headers: { "X-Custom": "value" }, + }, "token"); + + const options = mockFetch.mock.calls[0][1]; + expect(options.headers["Content-Type"]).toBe("application/json"); + expect(options.headers["X-Custom"]).toBe("value"); + expect(options.headers.Authorization).toBe("Bearer token"); + }); + + // ── 401 错误 ─────────────────────────────────────────────────────────── + + it("401 应抛出'登录已过期'错误", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: false, status: 401 }) + ); + + await expect(fetchWithAuth("/api/test", {}, "token")).rejects.toThrow( + "登录已过期,请重新登录" + ); + }); + + // ── 500 错误 ─────────────────────────────────────────────────────────── + + it("500 错误应抛出包含状态码的错误", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ + ok: false, + status: 500, + json: () => Promise.resolve({ detail: "内部服务器错误" }), + }) + ); + + await expect(fetchWithAuth("/api/test", {}, "token")).rejects.toThrow( + "内部服务器错误" + ); + }); + + it("500 错误且 JSON 解析失败应使用默认错误信息", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ + ok: false, + status: 500, + json: () => Promise.reject(new Error("invalid json")), + }) + ); + + await expect(fetchWithAuth("/api/test", {}, "token")).rejects.toThrow( + "请求失败 (HTTP 500)" + ); + }); + + it("其他错误状态码应正确抛出", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ + ok: false, + status: 422, + json: () => Promise.resolve({ detail: "参数校验失败" }), + }) + ); + + await expect(fetchWithAuth("/api/test", {}, "token")).rejects.toThrow( + "参数校验失败" + ); + }); + + // ── 成功响应 ──────────────────────────────────────────────────────────── + + it("200 应返回 JSON 数据", async () => { + const mockData = { id: "1", name: "品牌" }; + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ + ok: true, + status: 200, + json: () => Promise.resolve(mockData), + }) + ); + + const result = await fetchWithAuth("/api/test", {}, "token"); + expect(result).toEqual(mockData); + }); + + it("204 应返回 null", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ ok: true, status: 204 }) + ); + + const result = await fetchWithAuth("/api/test", {}, "token"); + expect(result).toBeNull(); + }); + + // ── 错误响应的 message 字段 ──────────────────────────────────────────── + + it("错误响应包含 message 字段时应优先使用", async () => { + mockFetch.mockResolvedValueOnce( + mockFetchResponse({ + ok: false, + status: 400, + json: () => Promise.resolve({ message: "品牌名称已存在" }), + }) + ); + + await expect(fetchWithAuth("/api/test", {}, "token")).rejects.toThrow( + "品牌名称已存在" + ); + }); +}); diff --git a/frontend/__tests__/stores/brand-store.test.ts b/frontend/__tests__/stores/brand-store.test.ts new file mode 100644 index 0000000..f76d226 --- /dev/null +++ b/frontend/__tests__/stores/brand-store.test.ts @@ -0,0 +1,440 @@ +/** + * Brand Store 单元测试 + * + * 覆盖:selectBrand / clearSelection / optimisticCreate / optimisticUpdate + */ + +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { useBrandStore } from "@/lib/stores/brand-store"; +import type { BrandListItem } from "@/types/brand"; + +// ── Mock 依赖 ──────────────────────────────────────────────────────────────── + +vi.mock("@/lib/api/client", () => ({ + fetchWithAuth: vi.fn(), +})); + +vi.mock("@/lib/api/brands", () => ({ + brandsApi: { + create: vi.fn(), + update: vi.fn(), + delete: vi.fn(), + }, +})); + +vi.mock("@/lib/stores/notification-store", () => ({ + useNotificationStore: { + getState: () => ({ + addNotification: vi.fn(), + }), + }, +})); + +// ── 测试数据 ───────────────────────────────────────────────────────────────── + +const MOCK_BRAND: BrandListItem = { + id: "brand-1", + name: "测试品牌", + aliases: ["测试"], + platforms: ["bing"], + frequency: "weekly", + status: "active", + score: 85, + last_queried_at: "2024-01-01T00:00:00Z", + next_query_at: "2024-01-08T00:00:00Z", + created_at: "2024-01-01T00:00:00Z", +}; + +const MOCK_BRAND_2: BrandListItem = { + id: "brand-2", + name: "另一个品牌", + aliases: [], + platforms: ["google"], + frequency: "daily", + status: "pending", + score: null, + last_queried_at: null, + next_query_at: null, + created_at: "2024-01-02T00:00:00Z", +}; + +// ── 测试 ────────────────────────────────────────────────────────────────────── + +describe("useBrandStore", () => { + beforeEach(() => { + // 重置 store 到初始状态 + useBrandStore.setState({ + selectedBrandId: null, + selectedBrandName: null, + localBrands: [], + optimisticAction: null, + }); + vi.clearAllMocks(); + }); + + // ── selectBrand / clearSelection ──────────────────────────────────────── + + describe("selectBrand / clearSelection", () => { + it("应正确选中品牌", () => { + const { selectBrand } = useBrandStore.getState(); + selectBrand("brand-1", "测试品牌"); + + const state = useBrandStore.getState(); + expect(state.selectedBrandId).toBe("brand-1"); + expect(state.selectedBrandName).toBe("测试品牌"); + }); + + it("选中品牌时 name 参数可选", () => { + const { selectBrand } = useBrandStore.getState(); + selectBrand("brand-2"); + + const state = useBrandStore.getState(); + expect(state.selectedBrandId).toBe("brand-2"); + expect(state.selectedBrandName).toBeNull(); + }); + + it("应正确清除选中品牌", () => { + useBrandStore.setState({ + selectedBrandId: "brand-1", + selectedBrandName: "测试品牌", + }); + + const { clearSelection } = useBrandStore.getState(); + clearSelection(); + + const state = useBrandStore.getState(); + expect(state.selectedBrandId).toBeNull(); + expect(state.selectedBrandName).toBeNull(); + }); + + it("切换选中品牌应覆盖旧值", () => { + useBrandStore.setState({ + selectedBrandId: "brand-1", + selectedBrandName: "旧品牌", + }); + + const { selectBrand } = useBrandStore.getState(); + selectBrand("brand-2", "新品牌"); + + const state = useBrandStore.getState(); + expect(state.selectedBrandId).toBe("brand-2"); + expect(state.selectedBrandName).toBe("新品牌"); + }); + }); + + // ── syncFromSWR ───────────────────────────────────────────────────────── + + describe("syncFromSWR", () => { + it("应同步 SWR 数据到本地副本", () => { + const { syncFromSWR } = useBrandStore.getState(); + syncFromSWR([MOCK_BRAND, MOCK_BRAND_2]); + + const state = useBrandStore.getState(); + expect(state.localBrands).toHaveLength(2); + expect(state.localBrands[0].id).toBe("brand-1"); + expect(state.localBrands[1].id).toBe("brand-2"); + }); + + it("多次同步应替换而非追加", () => { + const { syncFromSWR } = useBrandStore.getState(); + syncFromSWR([MOCK_BRAND]); + syncFromSWR([MOCK_BRAND_2]); + + const state = useBrandStore.getState(); + expect(state.localBrands).toHaveLength(1); + expect(state.localBrands[0].id).toBe("brand-2"); + }); + }); + + // ── optimisticCreate ──────────────────────────────────────────────────── + + describe("optimisticCreate", () => { + it("成功时应在本地添加临时条目后替换为真实数据", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + const created = vi.mocked(brandsApi.create).mockResolvedValueOnce( + MOCK_BRAND as never + ); + + const swrMutate = vi.fn(); + const { optimisticCreate } = useBrandStore.getState(); + + const result = await optimisticCreate( + "test-token", + { name: "测试品牌", platforms: ["bing"] }, + swrMutate + ); + + // 返回值应为 API 创建结果 + expect(result).toEqual(MOCK_BRAND); + + // 乐观操作状态已清除 + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // 本地列表应包含真实数据(非临时 ID) + const brands = useBrandStore.getState().localBrands; + expect(brands).toHaveLength(1); + expect(brands[0].id).toBe("brand-1"); + + // SWR mutate 应被调用 + expect(swrMutate).toHaveBeenCalled(); + }); + + it("失败时应回滚本地临时条目", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.create).mockRejectedValueOnce( + new Error("创建失败") as never + ); + + const swrMutate = vi.fn(); + const { optimisticCreate } = useBrandStore.getState(); + + const result = await optimisticCreate( + "test-token", + { name: "失败品牌" }, + swrMutate + ); + + // 返回 null + expect(result).toBeNull(); + + // 本地列表应回滚(为空) + expect(useBrandStore.getState().localBrands).toHaveLength(0); + + // 乐观操作状态已清除 + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // SWR mutate 不应被调用 + expect(swrMutate).not.toHaveBeenCalled(); + }); + + it("创建过程中 optimisticAction 应为 creating", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + let resolveCreate: (value: unknown) => void; + const createPromise = new Promise((resolve) => { + resolveCreate = resolve; + }); + vi.mocked(brandsApi.create).mockReturnValueOnce( + createPromise as never + ); + + const { optimisticCreate } = useBrandStore.getState(); + const createResult = optimisticCreate("test-token", { name: "异步品牌" }); + + // API 调用期间 + expect(useBrandStore.getState().optimisticAction).toBe("creating"); + expect(useBrandStore.getState().localBrands).toHaveLength(1); + expect(useBrandStore.getState().localBrands[0].name).toBe("异步品牌"); + + // 解析 API + resolveCreate!(MOCK_BRAND); + await createResult; + + expect(useBrandStore.getState().optimisticAction).toBeNull(); + }); + }); + + // ── optimisticUpdate ──────────────────────────────────────────────────── + + describe("optimisticUpdate", () => { + beforeEach(() => { + useBrandStore.setState({ + localBrands: [MOCK_BRAND, MOCK_BRAND_2], + }); + }); + + it("成功时应在本地乐观更新后替换为 API 返回数据", async () => { + const updatedBrand: BrandListItem = { + ...MOCK_BRAND, + name: "更新后品牌", + }; + + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.update).mockResolvedValueOnce( + updatedBrand as never + ); + + const swrMutate = vi.fn(); + const { optimisticUpdate } = useBrandStore.getState(); + + const result = await optimisticUpdate( + "test-token", + "brand-1", + { name: "更新后品牌" }, + swrMutate + ); + + expect(result).toEqual(updatedBrand); + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // 本地列表应包含更新后的数据 + const brands = useBrandStore.getState().localBrands; + expect(brands.find((b) => b.id === "brand-1")?.name).toBe("更新后品牌"); + + expect(swrMutate).toHaveBeenCalled(); + }); + + it("失败时应回滚到原始数据", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.update).mockRejectedValueOnce( + new Error("更新失败") as never + ); + + const swrMutate = vi.fn(); + const { optimisticUpdate } = useBrandStore.getState(); + + const result = await optimisticUpdate( + "test-token", + "brand-1", + { name: "回滚品牌" }, + swrMutate + ); + + expect(result).toBeNull(); + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // 本地列表应回滚到原始数据 + const brands = useBrandStore.getState().localBrands; + expect(brands.find((b) => b.id === "brand-1")?.name).toBe("测试品牌"); + + expect(swrMutate).not.toHaveBeenCalled(); + }); + + it("本地无品牌时直接走 API", async () => { + useBrandStore.setState({ localBrands: [] }); + + const updatedBrand: BrandListItem = { ...MOCK_BRAND, name: "新品牌" }; + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.update).mockResolvedValueOnce( + updatedBrand as never + ); + + const swrMutate = vi.fn(); + const { optimisticUpdate } = useBrandStore.getState(); + + const result = await optimisticUpdate( + "test-token", + "brand-1", + { name: "新品牌" }, + swrMutate + ); + + expect(result).toEqual(updatedBrand); + expect(swrMutate).toHaveBeenCalled(); + }); + + it("更新过程中 optimisticAction 应为 updating", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + let resolveUpdate: (value: unknown) => void; + const updatePromise = new Promise((resolve) => { + resolveUpdate = resolve; + }); + vi.mocked(brandsApi.update).mockReturnValueOnce( + updatePromise as never + ); + + const { optimisticUpdate } = useBrandStore.getState(); + const updateResult = optimisticUpdate( + "test-token", + "brand-1", + { name: "异步更新" } + ); + + // API 调用期间 + expect(useBrandStore.getState().optimisticAction).toBe("updating"); + + // 本地应已乐观更新 + expect( + useBrandStore.getState().localBrands.find((b) => b.id === "brand-1")?.name + ).toBe("异步更新"); + + resolveUpdate!({ ...MOCK_BRAND, name: "异步更新" }); + await updateResult; + + expect(useBrandStore.getState().optimisticAction).toBeNull(); + }); + }); + + // ── optimisticDelete ──────────────────────────────────────────────────── + + describe("optimisticDelete", () => { + beforeEach(() => { + useBrandStore.setState({ + localBrands: [MOCK_BRAND, MOCK_BRAND_2], + selectedBrandId: null, + selectedBrandName: null, + }); + }); + + it("成功时应在本地移除品牌", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.delete).mockResolvedValueOnce(undefined as never); + + const swrMutate = vi.fn(); + const { optimisticDelete } = useBrandStore.getState(); + + const result = await optimisticDelete("test-token", "brand-1", swrMutate); + + expect(result).toBe(true); + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // 本地列表不再包含被删除品牌 + const brands = useBrandStore.getState().localBrands; + expect(brands).toHaveLength(1); + expect(brands.find((b) => b.id === "brand-1")).toBeUndefined(); + + expect(swrMutate).toHaveBeenCalled(); + }); + + it("失败时应恢复被删除的品牌", async () => { + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.delete).mockRejectedValueOnce( + new Error("删除失败") as never + ); + + const swrMutate = vi.fn(); + const { optimisticDelete } = useBrandStore.getState(); + + const result = await optimisticDelete("test-token", "brand-1", swrMutate); + + expect(result).toBe(false); + expect(useBrandStore.getState().optimisticAction).toBeNull(); + + // 本地列表应恢复被删除品牌 + const brands = useBrandStore.getState().localBrands; + expect(brands).toHaveLength(2); + expect(brands.find((b) => b.id === "brand-1")).toBeDefined(); + }); + + it("删除当前选中品牌时应清除选择", async () => { + useBrandStore.setState({ + selectedBrandId: "brand-1", + selectedBrandName: "测试品牌", + }); + + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.delete).mockResolvedValueOnce(undefined as never); + + const { optimisticDelete } = useBrandStore.getState(); + await optimisticDelete("test-token", "brand-1"); + + expect(useBrandStore.getState().selectedBrandId).toBeNull(); + expect(useBrandStore.getState().selectedBrandName).toBeNull(); + }); + + it("删除非选中品牌时不应影响选择", async () => { + useBrandStore.setState({ + selectedBrandId: "brand-1", + selectedBrandName: "测试品牌", + }); + + const { brandsApi } = await import("@/lib/api/brands"); + vi.mocked(brandsApi.delete).mockResolvedValueOnce(undefined as never); + + const { optimisticDelete } = useBrandStore.getState(); + await optimisticDelete("test-token", "brand-2"); + + expect(useBrandStore.getState().selectedBrandId).toBe("brand-1"); + expect(useBrandStore.getState().selectedBrandName).toBe("测试品牌"); + }); + }); +}); diff --git a/frontend/__tests__/stores/notification-store.test.ts b/frontend/__tests__/stores/notification-store.test.ts new file mode 100644 index 0000000..0b7475d --- /dev/null +++ b/frontend/__tests__/stores/notification-store.test.ts @@ -0,0 +1,232 @@ +/** + * Notification Store 单元测试 + * + * 覆盖:addNotification / removeNotification / clearAll / 自动过期清除 + */ + +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { useNotificationStore } from "@/lib/stores/notification-store"; + +describe("useNotificationStore", () => { + beforeEach(() => { + // 重置 store 到初始状态 + useNotificationStore.setState({ notifications: [] }); + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + // ── addNotification ──────────────────────────────────────────────────── + + describe("addNotification", () => { + it("应添加一条通知到队列", () => { + const { addNotification } = useNotificationStore.getState(); + const id = addNotification({ type: "success", message: "操作成功" }); + + expect(id).toBeTruthy(); + expect(id).toMatch(/^notif-/); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(1); + expect(notifications[0].type).toBe("success"); + expect(notifications[0].message).toBe("操作成功"); + }); + + it("应支持不同类型的通知", () => { + const { addNotification } = useNotificationStore.getState(); + + addNotification({ type: "success", message: "成功" }); + addNotification({ type: "error", message: "错误" }); + addNotification({ type: "warning", message: "警告" }); + addNotification({ type: "info", message: "信息" }); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(4); + expect(notifications[0].type).toBe("success"); + expect(notifications[1].type).toBe("error"); + expect(notifications[2].type).toBe("warning"); + expect(notifications[3].type).toBe("info"); + }); + + it("应支持可选标题", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "info", message: "消息", title: "标题" }); + + const { notifications } = useNotificationStore.getState(); + expect(notifications[0].title).toBe("标题"); + }); + + it("默认过期时间应按类型自动设置", () => { + const { addNotification } = useNotificationStore.getState(); + + addNotification({ type: "success", message: "成功" }); + addNotification({ type: "error", message: "错误" }); + addNotification({ type: "warning", message: "警告" }); + addNotification({ type: "info", message: "信息" }); + + const { notifications } = useNotificationStore.getState(); + expect(notifications[0].duration).toBe(3000); // success + expect(notifications[1].duration).toBe(5000); // error + expect(notifications[2].duration).toBe(4000); // warning + expect(notifications[3].duration).toBe(3000); // info + }); + + it("应支持自定义过期时间", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "success", message: "自定义", duration: 10000 }); + + const { notifications } = useNotificationStore.getState(); + expect(notifications[0].duration).toBe(10000); + }); + + it("duration 为 undefined 时应使用默认过期时间", () => { + const { addNotification } = useNotificationStore.getState(); + // 不传 duration,使用 error 类型的默认值 5000 + addNotification({ type: "error", message: "使用默认" }); + + const { notifications } = useNotificationStore.getState(); + expect(notifications[0].duration).toBe(5000); + }); + + it("每条通知应有唯一 ID", () => { + const { addNotification } = useNotificationStore.getState(); + const id1 = addNotification({ type: "info", message: "第一条" }); + const id2 = addNotification({ type: "info", message: "第二条" }); + + expect(id1).not.toBe(id2); + }); + }); + + // ── removeNotification ───────────────────────────────────────────────── + + describe("removeNotification", () => { + it("应移除指定 ID 的通知", () => { + const { addNotification, removeNotification } = + useNotificationStore.getState(); + + const id1 = addNotification({ type: "success", message: "保留" }); + const id2 = addNotification({ type: "error", message: "移除" }); + + removeNotification(id2); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(1); + expect(notifications[0].id).toBe(id1); + }); + + it("移除不存在的 ID 不应报错", () => { + const { addNotification, removeNotification } = + useNotificationStore.getState(); + + addNotification({ type: "info", message: "测试" }); + expect(() => removeNotification("non-existent")).not.toThrow(); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(1); + }); + + it("移除通知时应清除其定时器", () => { + const { addNotification, removeNotification } = + useNotificationStore.getState(); + + const id = addNotification({ type: "success", message: "提前移除" }); + removeNotification(id); + + // 快进超过默认过期时间,不应再触发移除(避免对空列表操作) + vi.advanceTimersByTime(5000); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(0); + }); + }); + + // ── 自动过期清除 ─────────────────────────────────────────────────────── + + describe("自动过期清除", () => { + it("到达过期时间后应自动移除通知", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "success", message: "3秒后过期" }); + + // 快进 3 秒 + vi.advanceTimersByTime(3000); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(0); + }); + + it("不同类型通知在不同时间过期", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "success", message: "3秒" }); + addNotification({ type: "error", message: "5秒" }); + + // 快进 3 秒,success 应被清除 + vi.advanceTimersByTime(3000); + expect(useNotificationStore.getState().notifications).toHaveLength(1); + expect(useNotificationStore.getState().notifications[0].type).toBe( + "error" + ); + + // 再快进 2 秒(共 5 秒),error 也应被清除 + vi.advanceTimersByTime(2000); + expect(useNotificationStore.getState().notifications).toHaveLength(0); + }); + + it("自定义 duration=0 的通知不会自动过期", () => { + const { addNotification } = useNotificationStore.getState(); + // duration=0 时 setTimeout(cb, 0) 会在下一个事件循环触发 + // 但 effectiveDuration !== null 为 true,所以会设置定时器 + // 这里测试 duration 传入 0 的行为 + addNotification({ type: "error", message: "0 毫秒过期", duration: 0 }); + + // 0 毫秒定时器应立即触发 + vi.advanceTimersByTime(1); + + const { notifications } = useNotificationStore.getState(); + expect(notifications).toHaveLength(0); + }); + + it("自定义 duration 应在指定时间后过期", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "info", message: "1秒过期", duration: 1000 }); + + vi.advanceTimersByTime(999); + expect(useNotificationStore.getState().notifications).toHaveLength(1); + + vi.advanceTimersByTime(1); + expect(useNotificationStore.getState().notifications).toHaveLength(0); + }); + }); + + // ── clearAll ──────────────────────────────────────────────────────────── + + describe("clearAll", () => { + it("应清空所有通知", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "success", message: "A" }); + addNotification({ type: "error", message: "B" }); + addNotification({ type: "warning", message: "C" }); + + expect(useNotificationStore.getState().notifications).toHaveLength(3); + + const { clearAll } = useNotificationStore.getState(); + clearAll(); + + expect(useNotificationStore.getState().notifications).toHaveLength(0); + }); + + it("clearAll 后定时器不应再触发", () => { + const { addNotification } = useNotificationStore.getState(); + addNotification({ type: "success", message: "3秒后过期" }); + + const { clearAll } = useNotificationStore.getState(); + clearAll(); + + // 快进超过过期时间 + vi.advanceTimersByTime(5000); + + expect(useNotificationStore.getState().notifications).toHaveLength(0); + }); + }); +}); diff --git a/frontend/app/(auth)/login/page.tsx b/frontend/app/(auth)/login/page.tsx index d408f86..8a2d639 100644 --- a/frontend/app/(auth)/login/page.tsx +++ b/frontend/app/(auth)/login/page.tsx @@ -2,7 +2,6 @@ import { useState } from "react"; import { signIn } from "next-auth/react"; -import { useRouter } from "next/navigation"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -17,7 +16,6 @@ import { } from "@/components/ui/card"; export default function LoginPage() { - const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); @@ -36,8 +34,10 @@ export default function LoginPage() { if (result?.error) { setError("邮箱或密码错误"); } else { - router.push("/dashboard"); - router.refresh(); + // 使用 window.location.href 进行完整页面加载,确保 SessionProvider + // 重新初始化并获取最新的 session cookie,避免客户端导航时 + // useSession() 读到旧的 unauthenticated 缓存状态导致跳回登录页 + window.location.href = "/dashboard"; } }; diff --git a/frontend/app/(dashboard)/brands/page.tsx b/frontend/app/(dashboard)/brands/page.tsx index 3ae8071..4c9673f 100644 --- a/frontend/app/(dashboard)/brands/page.tsx +++ b/frontend/app/(dashboard)/brands/page.tsx @@ -1,19 +1,19 @@ "use client"; -import { useEffect, useState, useCallback } from "react"; +import { useState, useEffect } from "react"; import { useSession } from "next-auth/react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { Skeleton } from "@/components/ui/skeleton"; import { BrandFormDialog, AddBrandButton, } from "@/components/brand/BrandFormDialog"; import { api } from "@/lib/api"; import { PLATFORM_MAP } from "@/lib/platforms"; +import { useNotificationStore, useBrandStore } from "@/lib/stores"; import type { BrandListItem, BrandListResponse } from "@/types/brand"; import { Search, Star, Calendar, Edit, Trash2 } from "lucide-react"; import { @@ -24,45 +24,50 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { useApi } from "@/lib/hooks/use-api"; +import { LoadingState, ErrorState, EmptyState } from "@/components/ui/api-states"; export default function BrandsPage() { const { data: session } = useSession(); const router = useRouter(); - const [brands, setBrands] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); const [deleteBrand, setDeleteBrand] = useState(null); const [deleting, setDeleting] = useState(false); - const fetchBrands = useCallback(async () => { - const token = session?.accessToken; - if (!token) return; + const { data: brandsResponse, isLoading: loading, error: apiError, refresh: fetchBrands } = + useApi("/api/v1/brands/"); - try { - setLoading(true); - const response = (await api.brands.list(token)) as BrandListResponse; - setBrands(response.items || []); - } catch (err) { - setError(err instanceof Error ? err.message : "加载品牌失败"); - } finally { - setLoading(false); - } - }, [session?.accessToken]); + const brands: BrandListItem[] = brandsResponse?.items ?? []; + const error = apiError?.message ?? null; + // 同步 SWR 数据到 brand-store + const syncFromSWR = useBrandStore((s) => s.syncFromSWR); useEffect(() => { - fetchBrands(); - }, [fetchBrands]); + if (brands.length > 0) { + syncFromSWR(brands); + } + }, [brands, syncFromSWR]); + + const addNotification = useNotificationStore((s) => s.addNotification); + const optimisticDelete = useBrandStore((s) => s.optimisticDelete); const handleDelete = async () => { if (!deleteBrand || !session?.accessToken) return; try { setDeleting(true); - await api.brands.delete(session.accessToken, deleteBrand.id); - setDeleteBrand(null); - fetchBrands(); + const success = await optimisticDelete( + session.accessToken, + deleteBrand.id, + fetchBrands + ); + if (success) { + setDeleteBrand(null); + } } catch (err) { - alert(err instanceof Error ? err.message : "删除失败"); + addNotification({ + type: "error", + message: err instanceof Error ? err.message : "删除失败", + }); } finally { setDeleting(false); } @@ -108,35 +113,22 @@ export default function BrandsPage() {

品牌管理

管理您的品牌监控列表

- - -
- {Array.from({ length: 3 }).map((_, i) => ( - - - - - - - - - - ))}
+ ); } if (error) { return ( -
-

{error}

- +
+
+
+

品牌管理

+

管理您的品牌监控列表

+
+
+
); } @@ -150,17 +142,12 @@ export default function BrandsPage() {

管理您的品牌监控列表

- -
-
- -
-

暂无品牌

-

- 添加您的第一个品牌,开始监控其在AI搜索中的表现 -

- -
+ } + message="暂无品牌" + description="添加您的第一个品牌,开始监控其在AI搜索中的表现" + action={} + /> ); } diff --git a/frontend/app/(dashboard)/dashboard/admin/page.tsx b/frontend/app/(dashboard)/dashboard/admin/page.tsx index 9c6737f..6b6e5af 100644 --- a/frontend/app/(dashboard)/dashboard/admin/page.tsx +++ b/frontend/app/(dashboard)/dashboard/admin/page.tsx @@ -1,7 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; -import { useSession } from "next-auth/react"; +import { useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -29,7 +28,11 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { api } from "@/lib/api"; +import { fetchWithAuth } from "@/lib/api/client"; +import type { AdminStatsData, AdminUser, AdminUserListResponse, AdminActionResponse } from "@/lib/api/admin"; +import { useApi } from "@/lib/hooks/use-api"; +import { LoadingState, ErrorState } from "@/components/ui/api-states"; +import { clsx } from "clsx"; import { Users, Search, @@ -44,26 +47,6 @@ import { ChevronRight, } from "lucide-react"; -interface StatsData { - total_users: number; - total_queries: number; - total_citations: number; - citation_rate: number; - today_active_users: number; -} - -interface AdminUser { - id: string; - email: string; - name: string | null; - plan: string; - is_active: boolean; - is_admin: boolean; - email_verified: boolean; - query_count: number; - created_at: string; -} - const PLAN_OPTIONS = [ { value: "free", label: "免费版" }, { value: "starter", label: "入门版" }, @@ -74,15 +57,9 @@ const PLAN_OPTIONS = [ const LIMIT = 10; export default function AdminPage() { - const { data: session } = useSession(); - const [stats, setStats] = useState(null); - const [users, setUsers] = useState([]); - const [totalUsers, setTotalUsers] = useState(0); const [skip, setSkip] = useState(0); const [search, setSearch] = useState(""); - const [loadingStats, setLoadingStats] = useState(false); - const [loadingUsers, setLoadingUsers] = useState(false); - const [error, setError] = useState(null); + const [mutationError, setMutationError] = useState(null); const [success, setSuccess] = useState(null); const [dialogOpen, setDialogOpen] = useState(false); @@ -91,48 +68,16 @@ export default function AdminPage() { const [selectedPlan, setSelectedPlan] = useState(""); const [actionLoading, setActionLoading] = useState(false); - const token = session?.accessToken; + const { data: stats, isLoading: loadingStats, error: statsError } = + useApi("/api/v1/admin/stats"); - useEffect(() => { - if (!token) return; - loadStats(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [token]); + const usersUrl = `/api/v1/admin/users?skip=${skip}&limit=${LIMIT}${search ? `&search=${encodeURIComponent(search)}` : ""}`; + const { data: usersData, isLoading: loadingUsers, error: usersError, refresh: refreshUsers } = + useApi(usersUrl); - useEffect(() => { - if (!token) return; - loadUsers(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [token, skip, search]); - - async function loadStats() { - if (!token) return; - setLoadingStats(true); - try { - const data = await api.admin.getStats(token); - setStats(data); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "加载统计失败"); - } finally { - setLoadingStats(false); - } - } - - async function loadUsers() { - if (!token) return; - setLoadingUsers(true); - try { - const data = await api.admin.getUsers(token, { skip, limit: LIMIT, search: search || undefined }); - setUsers(data.items || []); - setTotalUsers(data.total || 0); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "加载用户列表失败"); - } finally { - setLoadingUsers(false); - } - } + const users: AdminUser[] = usersData?.items ?? []; + const totalUsers = usersData?.total ?? 0; + const error = mutationError || statsError?.message || usersError?.message || null; function openToggleDialog(user: AdminUser) { setSelectedUser(user); @@ -148,22 +93,29 @@ export default function AdminPage() { } async function handleConfirm() { - if (!token || !selectedUser) return; + if (!selectedUser) return; setActionLoading(true); setSuccess(null); + setMutationError(null); try { if (dialogType === "toggle") { - const res = await api.admin.toggleUserActive(token, selectedUser.id); + const res = await fetchWithAuth( + `/api/v1/admin/users/${selectedUser.id}/toggle-active`, + { method: "POST" } + ) as AdminActionResponse; setSuccess(res.message || "操作成功"); } else { - const res = await api.admin.updateUserPlan(token, selectedUser.id, selectedPlan); + const res = await fetchWithAuth( + `/api/v1/admin/users/${selectedUser.id}/update-plan`, + { method: "PUT", body: JSON.stringify({ plan: selectedPlan }) } + ) as AdminActionResponse; setSuccess(res.message || "套餐更新成功"); } - await loadUsers(); + refreshUsers(); setDialogOpen(false); setTimeout(() => setSuccess(null), 3000); } catch (err) { - setError(err instanceof Error ? err.message : "操作失败"); + setMutationError(err instanceof Error ? err.message : "操作失败"); setDialogOpen(false); } finally { setActionLoading(false); @@ -210,6 +162,19 @@ export default function AdminPage() { return d.toLocaleDateString("zh-CN"); } + if (loadingStats && !stats) { + return ( +
+
+

管理后台

+

系统统计与用户管理

+
+ + +
+ ); + } + return (
@@ -236,8 +201,8 @@ export default function AdminPage() { {statCards.map((card) => ( -
- +
+

{card.title}

@@ -271,88 +236,92 @@ export default function AdminPage() {
-
- - - - 邮箱 - 用户名 - 套餐 - 查询数 - 邮箱验证 - 状态 - 注册日期 - 操作 - - - - {loadingUsers ? ( + {usersError ? ( + + ) : ( +
+
+ - - - + 邮箱 + 用户名 + 套餐 + 查询数 + 邮箱验证 + 状态 + 注册日期 + 操作 - ) : users.length === 0 ? ( - - - 暂无用户数据 - - - ) : ( - users.map((user) => ( - - {user.email} - {user.name || "-"} - - {user.plan} - - {user.query_count} - - {user.email_verified ? ( - - 已验证 - - ) : ( - - 未验证 - - )} - - - {user.is_active ? ( - - 正常 - - ) : ( - 禁用 - )} - - {formatDate(user.created_at)} - -
- - -
+
+ + {loadingUsers ? ( + + + - )) - )} - -
-
+ ) : users.length === 0 ? ( + + + 暂无用户数据 + + + ) : ( + users.map((user) => ( + + {user.email} + {user.name || "-"} + + {user.plan} + + {user.query_count} + + {user.email_verified ? ( + + 已验证 + + ) : ( + + 未验证 + + )} + + + {user.is_active ? ( + + 正常 + + ) : ( + 禁用 + )} + + {formatDate(user.created_at)} + +
+ + +
+
+
+ )) + )} + + +
+ )} {/* Pagination */} {totalPages > 1 && ( @@ -428,7 +397,3 @@ export default function AdminPage() {
); } - -function cn(...classes: (string | undefined | false)[]) { - return classes.filter(Boolean).join(" "); -} diff --git a/frontend/app/(dashboard)/dashboard/analytics/page.tsx b/frontend/app/(dashboard)/dashboard/analytics/page.tsx index b8877f7..ba010a8 100644 --- a/frontend/app/(dashboard)/dashboard/analytics/page.tsx +++ b/frontend/app/(dashboard)/dashboard/analytics/page.tsx @@ -1,10 +1,9 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { Skeleton } from "@/components/ui/skeleton"; import { Table, TableBody, @@ -23,8 +22,6 @@ import { AlertTriangle, Check, BarChart3, - AlertCircle, - RefreshCw, } from "lucide-react"; import { BarChart, @@ -44,6 +41,8 @@ import { type TopContentItem, type InsightResponse, } from "@/lib/api"; +import { useApi } from "@/lib/hooks/use-api"; +import { LoadingState, ErrorState } from "@/components/ui/api-states"; // ─── Types ─────────────────────────────────────────────────────────────────── @@ -177,45 +176,30 @@ function MetricCard({ subtext?: string; }) { return ( - - -
-
- {icon} -
- {highlight && ( - - GEO核心指标 - - )} +
+
+

{label}

+
+ {icon}
-
-

- {typeof value === "number" ? value.toLocaleString() : value} -

-

{label}

- {subtext &&

{subtext}

} -
- - +
+

+ {typeof value === "number" ? value.toLocaleString() : value} +

+ {subtext &&

{subtext}

} +
); } function EmptyTopContent() { return (
- -

暂无发布内容数据

-

发布内容后这里将展示表现排行榜

+ +

暂无发布内容数据

+

发布内容后这里将展示表现排行榜

); } @@ -223,9 +207,9 @@ function EmptyTopContent() { function EmptyInsights() { return (
- -

暂无AI洞察

-

积累更多数据后,AI将为您生成优化建议

+ +

暂无AI洞察

+

积累更多数据后,AI将为您生成优化建议

); } @@ -235,35 +219,52 @@ function EmptyInsights() { export default function AnalyticsPage() { const [selectedPlatforms, setSelectedPlatforms] = useState([]); const [timeRange, setTimeRange] = useState("30"); + const [appliedInsights, setAppliedInsights] = useState>(new Set()); - const [overview, setOverview] = useState(null); - const [topContent, setTopContent] = useState([]); - const [insights, setInsights] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + // SWR 数据获取 + const { + data: overview, + isLoading: overviewLoading, + error: overviewError, + refresh: refreshOverview, + } = useApi("/api/v1/analytics/overview"); - useEffect(() => { - async function fetchAnalyticsData() { - try { - setLoading(true); - setError(null); - const [overviewData, topData, insightsData] = await Promise.all([ - analyticsApi.getOverview(), - analyticsApi.getTopContent(undefined, { limit: 5 }), - analyticsApi.getInsights(undefined, { limit: 6 }), - ]); - setOverview(overviewData); - setTopContent(topData?.items ?? []); - setInsights(mapApiInsights(insightsData ?? [])); - } catch (err) { - console.error("Analytics fetch error:", err); - setError(err instanceof Error ? err.message : "数据加载失败"); - } finally { - setLoading(false); - } - } - fetchAnalyticsData(); - }, []); + const { + data: topContentData, + isLoading: topLoading, + error: topError, + refresh: refreshTop, + } = useApi<{ items: TopContentItem[]; sort_by: string; total: number }>("/api/v1/analytics/top?limit=5"); + + const { + data: insightsData, + isLoading: insightsLoading, + error: insightsError, + refresh: refreshInsights, + } = useApi("/api/v1/analytics/insights?limit=6"); + + const loading = overviewLoading || topLoading || insightsLoading; + + // "用户未关联组织" 类错误视为空状态 + const isOrgError = (err: Error | undefined) => + err?.message.includes("未关联组织") || err?.message.includes("No organization"); + + const hasOrgError = isOrgError(overviewError) || isOrgError(topError) || isOrgError(insightsError); + const error = !hasOrgError && (overviewError || topError || insightsError) + ? overviewError || topError || insightsError + : undefined; + + const topContent: TopContentItem[] = topContentData?.items ?? []; + const rawInsights: InsightResponse[] = insightsData ?? []; + const insights = mapApiInsights(rawInsights).map((ins) => + appliedInsights.has(ins.id) ? { ...ins, applied: true } : ins + ); + + const handleRetry = () => { + refreshOverview(); + refreshTop(); + refreshInsights(); + }; const togglePlatform = (key: string) => { setSelectedPlatforms((prev) => @@ -274,9 +275,7 @@ export default function AnalyticsPage() { const handleApplyInsight = async (insightId: string) => { try { await analyticsApi.applyInsight(undefined, insightId); - setInsights((prev) => - prev.map((ins) => (ins.id === insightId ? { ...ins, applied: true } : ins)) - ); + setAppliedInsights((prev) => new Set(prev).add(insightId)); } catch (err) { console.error("Apply insight error:", err); } @@ -285,14 +284,10 @@ export default function AnalyticsPage() { if (loading) { return (
- -
- {Array.from({ length: 4 }).map((_, i) => ( - - ))} -
- - + + + +
); } @@ -300,16 +295,8 @@ export default function AnalyticsPage() { if (error) { return (
-

数据监测中心

-
- -

数据加载失败

-

{error}

- -
+

数据监测中心

+
); } @@ -324,12 +311,12 @@ export default function AnalyticsPage() { return (
{/* Top Area */} -
+
-

+

数据监测中心

-

+

全渠道内容表现追踪与AI引用洞察

@@ -379,27 +366,26 @@ export default function AnalyticsPage() { } + icon={} iconBg="bg-blue-50" /> } + icon={} iconBg="bg-purple-50" /> } + icon={} iconBg="bg-amber-50" /> } - iconBg="bg-primary/10" - highlight + icon={} + iconBg="bg-emerald-50" subtext={ overview?.avg_engagement_rate ? `互动率 ${(overview.avg_engagement_rate * 100).toFixed(1)}%` @@ -408,15 +394,14 @@ export default function AnalyticsPage() { />
- {/* Trend Chart — platform distribution */} - - -
-

平台内容分布

- - 实时数据 - -
+ {/* Trend Chart */} +
+
+

平台内容分布

+ + 实时数据 + +
{trendData.length > 0 ? ( @@ -437,8 +422,8 @@ export default function AnalyticsPage() { /> ) : (
- -

暂无平台分布数据

+ +

暂无平台分布数据

)} - - +
{/* Performance Table */} - - -
-

内容表现排行榜

- - Top {topContent.length} - -
+
+
+

内容表现排行榜

+ + Top {topContent.length} + +
{topContent.length === 0 ? ( ) : ( @@ -482,12 +465,12 @@ export default function AnalyticsPage() { - 排名 - 标题 - 平台 - 曝光 - 互动率 - AI引用数 + 排名 + 标题 + 平台 + 曝光 + 互动率 + AI引用数 @@ -498,7 +481,7 @@ export default function AnalyticsPage() { ? ((item.search_clicks / item.search_impressions) * 100).toFixed(1) : "0.0"; return ( - + - + {item.content_title} @@ -522,10 +505,10 @@ export default function AnalyticsPage() { {item.platform} - + {(item.views || item.search_impressions).toLocaleString()} - + {interactionRate}% @@ -541,40 +524,37 @@ export default function AnalyticsPage() {
)} -
-
+
{/* AI Insights */} -
-

+
+

AI 智能洞察

{insights.length === 0 ? ( - - - - - +
+ +
) : (
{insights.map((insight) => { const styles = getSeverityStyles(insight.severity); return ( -
-
- +
+
-

+

{insight.title}

-

+

{insight.description}

{insight.recommendation && ( @@ -597,7 +577,7 @@ export default function AnalyticsPage() {
- +
); })}
diff --git a/frontend/app/(dashboard)/dashboard/citations/page.tsx b/frontend/app/(dashboard)/dashboard/citations/page.tsx index 351026b..7e3df9d 100644 --- a/frontend/app/(dashboard)/dashboard/citations/page.tsx +++ b/frontend/app/(dashboard)/dashboard/citations/page.tsx @@ -1,7 +1,6 @@ "use client"; -import { useEffect, useRef, useState } from "react"; -import { useSession } from "next-auth/react"; +import { useState } from "react"; import { Table, TableBody, @@ -22,9 +21,10 @@ import { SelectValue, } from "@/components/ui/select"; import { Button } from "@/components/ui/button"; -import { api } from "@/lib/api"; import { PLATFORM_MAP } from "@/lib/platforms"; -import { Check, X, Loader2, Quote, Filter } from "lucide-react"; +import { Check, X, Quote, Filter } from "lucide-react"; +import { useApi } from "@/lib/hooks/use-api"; +import { LoadingState } from "@/components/ui/api-states"; interface CitationItem { id: string; @@ -43,69 +43,44 @@ interface QueryOption { } export default function CitationsPage() { - const { data: session } = useSession(); - const [citations, setCitations] = useState([]); - const [queries, setQueries] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [selectedQuery, setSelectedQuery] = useState("all"); const [selectedPlatform, setSelectedPlatform] = useState("all"); const [startDate, setStartDate] = useState(""); const [endDate, setEndDate] = useState(""); - const isFirstFilterEffect = useRef(true); + // 用于手动触发筛选 + const [filterKey, setFilterKey] = useState(0); - useEffect(() => { - if (!session?.accessToken) return; - loadQueries(); - loadCitations(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [session?.accessToken]); + // 构建引用记录查询 URL + const citationsUrl = (() => { + const params = new URLSearchParams(); + if (selectedQuery && selectedQuery !== "all") params.append("query_id", selectedQuery); + if (selectedPlatform && selectedPlatform !== "all") params.append("platform", selectedPlatform); + if (startDate) params.append("start_date", startDate); + if (endDate) params.append("end_date", endDate); + const qs = params.toString(); + // filterKey 作为虚拟参数,即使筛选条件不变也允许重新请求 + return `/api/v1/citations/${qs ? `?${qs}&_k=${filterKey}` : `?_k=${filterKey}`}`; + })(); - useEffect(() => { - if (!session?.accessToken) return; - if (isFirstFilterEffect.current) { - isFirstFilterEffect.current = false; - return; - } - loadCitations(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedQuery, selectedPlatform, startDate, endDate, session?.accessToken]); + const { + data: citationsData, + isLoading, + error: citationsError, + refresh: refreshCitations, + } = useApi<{ items: CitationItem[] }>( + citationsUrl, + { dedupingInterval: 0 } + ); - async function loadQueries() { - try { - const data = await api.queries.list(session!.accessToken); - setQueries(data.items || []); - } catch { - // 静默失败,查询词筛选为非必需 - } - } + const { + data: queriesData, + } = useApi<{ items: QueryOption[] }>("/api/v1/queries/"); - async function loadCitations() { - if (!session?.accessToken) return; - try { - setLoading(true); - const params = new URLSearchParams(); - if (selectedQuery && selectedQuery !== "all") params.append("query_id", selectedQuery); - if (selectedPlatform && selectedPlatform !== "all") params.append("platform", selectedPlatform); - if (startDate) params.append("start_date", startDate); - if (endDate) params.append("end_date", endDate); - - const data = await api.citations.list( - session.accessToken, - params.toString() - ); - setCitations(data.items || []); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "加载引用记录失败"); - } finally { - setLoading(false); - } - } + const citations: CitationItem[] = citationsData?.items ?? []; + const queries: QueryOption[] = queriesData?.items ?? []; function handleFilter() { - loadCitations(); + setFilterKey((k) => k + 1); } function handleReset() { @@ -113,18 +88,17 @@ export default function CitationsPage() { setSelectedPlatform("all"); setStartDate(""); setEndDate(""); + setFilterKey((k) => k + 1); } - if (loading && citations.length === 0) { + if (isLoading && citations.length === 0) { return (

引用记录

查看各平台的引用检测结果

-
- -
+
); } @@ -207,9 +181,9 @@ export default function CitationsPage() {
- {error && ( + {citationsError && (
- {error} + {citationsError.message}
)} diff --git a/frontend/app/(dashboard)/dashboard/content/page.tsx b/frontend/app/(dashboard)/dashboard/content/page.tsx index f52edfc..016433a 100644 --- a/frontend/app/(dashboard)/dashboard/content/page.tsx +++ b/frontend/app/(dashboard)/dashboard/content/page.tsx @@ -134,10 +134,10 @@ function ContentCard({ item }: { item: Content }) { const dateStr = new Date(item.created_at).toLocaleDateString("zh-CN"); return ( - - +
+
-

+

{item.title}

@@ -149,7 +149,7 @@ function ContentCard({ item }: { item: Content }) { {statusConfig.label}
-
+
@@ -166,8 +166,8 @@ function ContentCard({ item }: { item: Content }) { )}
- - +
+
); } @@ -226,17 +226,17 @@ function PipelineTimeline({ steps }: { steps: PipelineStep[] }) { function EmptyState({ onGenerate }: { onGenerate: () => void }) { return ( -
-
- +
+
+
-

还没有内容

-

+

还没有内容

+

让AI帮你创作第一篇内容,开启智能内容生产之旅

+ +
+
) : recommendations.length > 0 ? (
{recommendations.map((comp) => { diff --git a/frontend/app/(dashboard)/onboarding/Step4HealthReport.tsx b/frontend/app/(dashboard)/onboarding/Step4HealthReport.tsx index db674d6..46c81e1 100644 --- a/frontend/app/(dashboard)/onboarding/Step4HealthReport.tsx +++ b/frontend/app/(dashboard)/onboarding/Step4HealthReport.tsx @@ -46,52 +46,31 @@ export function Step4HealthReport({ const { data: session } = useSession(); const [report, setReport] = useState(null); const [loading, setLoading] = useState(true); - const [error] = useState(null); + const [error, setError] = useState(null); + + const fetchReport = async () => { + if (!session?.accessToken) return; + + try { + setLoading(true); + setError(null); + const data = (await api.onboarding.getHealthReport( + session.accessToken, + brandId, + )) as BrandHealthReport; + setReport(data); + } catch (err) { + console.error("获取健康报告失败:", err); + setError("获取健康报告失败,请重试"); + } finally { + setLoading(false); + } + }; useEffect(() => { - const fetchReport = async () => { - if (!session?.accessToken) return; - - try { - setLoading(true); - const data = (await api.onboarding.getHealthReport( - session.accessToken, - brandId, - )) as BrandHealthReport; - setReport(data); - } catch (err) { - console.error("获取健康报告失败:", err); - // 使用模拟数据 - setReport({ - brand_id: brandId, - brand_name: brandName, - overall_score: 68, - platform_scores: { - wenxin: 72, - kimi: 65, - tongyi: 70, - baidu_ai: 68, - yuanbao: 60, - qingyan: 75, - doubao: 62, - }, - competitor_scores: [ - { name: "竞品A", score: 75, is_leading: false }, - { name: "竞品B", score: 58, is_leading: true }, - { name: "竞品C", score: 82, is_leading: false }, - ], - strengths: ["在Kimi平台表现优秀", "品牌提及率稳定"], - weaknesses: ["在腾讯元宝平台覆盖率低", "内容质量有待提升"], - }); - } finally { - setLoading(false); - } - }; - - // 模拟加载时间 - const timer = setTimeout(fetchReport, 1500); - return () => clearTimeout(timer); - }, [session?.accessToken, brandId, brandName]); + fetchReport(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [session?.accessToken, brandId]); if (loading) { return ( @@ -120,7 +99,7 @@ export function Step4HealthReport({ ); } - if (error || !report) { + if (error || (!loading && !report)) { return (
@@ -138,12 +117,24 @@ export function Step4HealthReport({ 上一步 - + +
); } + // TypeScript 类型守卫:经过 loading 和 error 检查后,report 必定存在 + if (!report) return null; + const healthLevel = getHealthLevel(report.overall_score); const healthConfig = HEALTH_LEVELS[healthLevel]; diff --git a/frontend/app/(dashboard)/onboarding/Step5ActionSuggestions.tsx b/frontend/app/(dashboard)/onboarding/Step5ActionSuggestions.tsx index 243fddc..3ae7c90 100644 --- a/frontend/app/(dashboard)/onboarding/Step5ActionSuggestions.tsx +++ b/frontend/app/(dashboard)/onboarding/Step5ActionSuggestions.tsx @@ -18,6 +18,7 @@ import { ArrowLeft, CheckCircle2, LayoutDashboard, + AlertTriangle, } from "lucide-react"; import { api } from "@/lib/api"; import type { ActionSuggestion } from "@/types/onboarding"; @@ -62,61 +63,30 @@ export function Step5ActionSuggestions({ const [suggestions, setSuggestions] = useState([]); const [loading, setLoading] = useState(true); const [completing, setCompleting] = useState(false); - const [error] = useState(null); + const [error, setError] = useState(null); + + const fetchSuggestions = async () => { + if (!session?.accessToken) return; + + try { + setLoading(true); + setError(null); + const data = (await api.onboarding.getActionSuggestions( + session.accessToken, + brandId, + )) as ActionSuggestion[]; + setSuggestions(data || []); + } catch (err) { + console.error("获取行动建议失败:", err); + setError("获取行动建议失败,请重试"); + } finally { + setLoading(false); + } + }; useEffect(() => { - const fetchSuggestions = async () => { - if (!session?.accessToken) return; - - try { - setLoading(true); - const data = (await api.onboarding.getActionSuggestions( - session.accessToken, - brandId, - )) as ActionSuggestion[]; - setSuggestions(data || []); - } catch (err) { - console.error("获取行动建议失败:", err); - // 使用模拟数据 - setSuggestions([ - { - id: "1", - title: "优化腾讯元宝平台内容", - description: - "在腾讯元宝平台的搜索结果中曝光率较低,建议增加相关内容布局", - priority: "high", - action_type: "improve_platform", - }, - { - id: "2", - title: "提升整体内容质量", - description: "内容被引用率偏低,建议优化内容的专业性和权威性", - priority: "high", - action_type: "optimize_content", - }, - { - id: "3", - title: "添加新的竞品对手", - description: "建议添加3个新的竞品以获得更全面的对比分析", - priority: "medium", - action_type: "add_competitor", - }, - { - id: "4", - title: "提高查询频率", - description: "当前每周查询可能错过重要信息,建议调整为每日查询", - priority: "low", - action_type: "increase_frequency", - }, - ]); - } finally { - setLoading(false); - } - }; - - // 模拟加载时间 - const timer = setTimeout(fetchSuggestions, 1000); - return () => clearTimeout(timer); + fetchSuggestions(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [session?.accessToken, brandId]); const handleComplete = async () => { @@ -166,6 +136,25 @@ export function Step5ActionSuggestions({ ); } + // 错误状态 + if (!loading && error) { + return ( +
+
+
+ +
+

获取建议失败

+

{error}

+
+
+ + +
+
+ ); + } + // 按优先级分组 const highPriority = suggestions.filter((s) => s.priority === "high"); const mediumPriority = suggestions.filter((s) => s.priority === "medium"); diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 1cd3c28..2586026 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -28,11 +28,14 @@ --radius: 1rem; /* 16px base radius */ /* GEO Custom tokens */ - --geo-nav-bg: #1a1f2e; - --geo-nav-hover: #252b3b; + --geo-nav-bg: #FFFFFF; + --geo-nav-hover: #F3F4F6; --geo-nav-active: #10B981; - --geo-shadow-card: 0 2px 8px 0 rgba(0,0,0,0.06); - --geo-shadow-card-hover: 0 8px 24px 0 rgba(0,0,0,0.10); + --geo-nav-text: #374151; + --geo-nav-text-active: #059669; + --geo-nav-active-bg: #ECFDF5; + --geo-shadow-card: 0 1px 3px rgba(0,0,0,0.04); + --geo-shadow-card-hover: 0 4px 12px rgba(0,0,0,0.06); --geo-transition: 200ms ease; } @@ -84,7 +87,7 @@ @apply bg-white rounded-lg border border-geo-border shadow-card transition-all duration-200; } .geo-card:hover { - @apply -translate-y-0.5 shadow-card-hover; + @apply shadow-card-hover border-primary/30; } /* GEO Scrollbar */ diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index e556400..3eb33b1 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import localFont from "next/font/local"; import "./globals.css"; import { Providers } from "@/components/providers"; +import { ErrorBoundary } from "@/components/ErrorBoundary"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -29,7 +30,9 @@ export default function RootLayout({ - {children} + + {children} + ); diff --git a/frontend/components/ErrorBoundary.tsx b/frontend/components/ErrorBoundary.tsx new file mode 100644 index 0000000..ee436ba --- /dev/null +++ b/frontend/components/ErrorBoundary.tsx @@ -0,0 +1,130 @@ +"use client"; + +/** + * 全局错误边界组件 + * + * - 捕获子树中的 React 渲染错误,防止整个页面白屏 + * - 在开发环境输出详细错误栈到 console + * - 预留 Sentry 集成点(搜索 TODO:SENTRY) + * - 提供可重置的友好错误 UI + */ + +import React, { Component, ErrorInfo, ReactNode } from "react"; + +interface Props { + children: ReactNode; + /** 自定义 fallback UI;不传则使用内置样式 */ + fallback?: ReactNode; +} + +interface State { + hasError: boolean; + error: Error | null; + errorInfo: ErrorInfo | null; +} + +export class ErrorBoundary extends Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false, error: null, errorInfo: null }; + } + + static getDerivedStateFromError(error: Error): Partial { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo): void { + this.setState({ errorInfo }); + + // 开发环境:完整错误栈 + if (process.env.NODE_ENV !== "production") { + console.group("[ErrorBoundary] 捕获到未处理的渲染错误"); + console.error("Error:", error); + console.error("Component Stack:", errorInfo.componentStack); + console.groupEnd(); + } else { + console.error("[ErrorBoundary]", error.message); + } + + // TODO:SENTRY — 生产环境错误上报 + // import * as Sentry from "@sentry/nextjs"; + // Sentry.captureException(error, { extra: { componentStack: errorInfo.componentStack } }); + } + + handleReset = (): void => { + this.setState({ hasError: false, error: null, errorInfo: null }); + }; + + render(): ReactNode { + if (!this.state.hasError) { + return this.props.children; + } + + // 使用自定义 fallback + if (this.props.fallback) { + return this.props.fallback; + } + + // 内置友好错误页面 + return ( +
+
+ {/* 图标 */} +
+ +
+ +

+ 页面出现了错误 +

+

+ 应用遇到了一个意外错误。您可以尝试刷新页面,或点击下方按钮重试。 +

+ + {/* 开发环境:展示错误摘要 */} + {process.env.NODE_ENV !== "production" && this.state.error && ( +
+ + 错误详情(开发模式) + +
+                {this.state.error.message}
+                {this.state.errorInfo?.componentStack}
+              
+
+ )} + +
+ + +
+
+
+ ); + } +} + +export default ErrorBoundary; diff --git a/frontend/components/business/metric-card.tsx b/frontend/components/business/metric-card.tsx index ea220c4..8ae070b 100644 --- a/frontend/components/business/metric-card.tsx +++ b/frontend/components/business/metric-card.tsx @@ -2,7 +2,6 @@ import * as React from "react"; import { cn } from "@/lib/utils"; -import { Card } from "@/components/ui/card"; export type TrendDirection = "up" | "down" | "neutral"; @@ -31,59 +30,6 @@ export interface MetricCardProps extends React.HTMLAttributes { size?: "sm" | "default" | "lg"; } -const TrendArrow = ({ direction }: { direction: TrendDirection }) => { - if (direction === "neutral") return null; - const isUp = direction === "up"; - return ( - - {isUp ? ( - - ) : ( - - )} - - ); -}; - -const Sparkline = ({ data, trend }: { data: SparklinePoint[]; trend?: TrendDirection }) => { - if (!data || data.length < 2) return null; - const max = Math.max(...data.map((d) => d.value)); - const min = Math.min(...data.map((d) => d.value)); - const range = max - min || 1; - const width = 80; - const height = 28; - const points = data.map((d, i) => { - const x = (i / (data.length - 1)) * width; - const y = height - ((d.value - min) / range) * height; - return `${x},${y}`; - }); - const isUp = trend !== "down"; - return ( - - - {/* last dot */} - - - ); -}; - const MetricCard = React.forwardRef( ( { @@ -114,80 +60,64 @@ const MetricCard = React.forwardRef( }[size]; return ( - -
- {/* Label row */} -
-

- {label} -

- {icon && ( -
- {icon} -
+
+ {/* Left color bar */} +
+ /> - {/* Value + sparkline row */} -
-
- - {value} - - {subValue && ( - {subValue} - )} -
- {sparklineData && sparklineData.length >= 2 && ( -
- -
- )} -
- - {/* Trend row */} - {(trendValue || trendLabel) && ( -
+ {/* Content */} +
+ {/* Label row */} +
+

+ {label} +

{trendValue && ( -
- - {trendValue} -
- )} - {trendLabel && ( - {trendLabel} + {trend === "up" && "+"}{trendValue} + )}
- )} -
- {/* subtle background accent */} -
- + {/* Value */} +

+ {value} +

+ + {/* Trend label */} + {trendLabel && ( +

{trendLabel}

+ )} +
+
+
); } ); diff --git a/frontend/components/layout/header.tsx b/frontend/components/layout/header.tsx index e20d385..502f4b2 100644 --- a/frontend/components/layout/header.tsx +++ b/frontend/components/layout/header.tsx @@ -1,30 +1,38 @@ "use client"; -import { useSession, signOut } from "next-auth/react"; -import { Button } from "@/components/ui/button"; -import { LogOut, User } from "lucide-react"; +import { useSession } from "next-auth/react"; +import { Search, Bell } from "lucide-react"; import { AlertBell } from "@/components/layout/alert-bell"; export function Header() { const { data: session } = useSession(); + const userName = session?.user?.name || session?.user?.email || "用户"; + const initials = userName.slice(0, 2).toUpperCase(); return ( -
-

GEO Platform

+
+ {/* Left: Search */} +
+ + +
+ + {/* Right: Actions */}
+ {/* Notification bell */} -
- - {session?.user?.name || session?.user?.email || "用户"} + + {/* User avatar + name */} +
+
+ {initials} +
+ {userName}
-
); diff --git a/frontend/components/layout/side-nav.tsx b/frontend/components/layout/side-nav.tsx index fbb4881..5e3e537 100644 --- a/frontend/components/layout/side-nav.tsx +++ b/frontend/components/layout/side-nav.tsx @@ -20,50 +20,29 @@ export interface NavGroup { items: NavItem[]; } -export interface SideNavUser { - name: string; - email?: string; - avatar?: string; - /** 完成度 0-100 */ - completionPercent?: number; - completionLabel?: string; -} - export interface SideNavProps extends React.HTMLAttributes { - /** 品牌 Logo/名称区域 */ - logo?: React.ReactNode; /** 品牌名 */ brandName?: string; + /** 品牌图标 */ + brandIcon?: React.ReactNode; /** 导航分组 */ groups: NavGroup[]; /** 当前激活的导航项 id */ activeId?: string; /** 导航项点击回调 */ onNavClick?: (item: NavItem) => void; - /** 底部用户信息 */ - user?: SideNavUser; - /** 底部额外操作区 */ - footerExtra?: React.ReactNode; - /** 是否折叠(仅展示图标) */ - collapsed?: boolean; - /** 折叠切换回调 */ - onCollapsedChange?: (collapsed: boolean) => void; - /** "更多工具"分组标签 */ - moreToolsLabel?: string; } -// ─── Sub-components ──────────────────────────────────────────────────────────── +// ─── NavItemRow ─────────────────────────────────────────────────────────────── const NavItemRow = React.memo( ({ item, active, - collapsed, onClick, }: { item: NavItem; active: boolean; - collapsed?: boolean; onClick?: () => void; }) => { return ( @@ -71,28 +50,21 @@ const NavItemRow = React.memo( type="button" disabled={item.disabled} onClick={onClick} - title={collapsed ? item.label : undefined} className={cn( - "group relative flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200", - "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-geo-nav-active focus-visible:ring-offset-1 focus-visible:ring-offset-geo-nav", + "group relative flex w-full items-center gap-3 rounded-lg py-2.5 px-4 text-sm font-medium transition-all duration-150", + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-1", "disabled:pointer-events-none disabled:opacity-40", active - ? "bg-geo-nav-active/15 text-geo-nav-active" - : "text-white/70 hover:bg-white/8 hover:text-white", - collapsed && "justify-center px-2" + ? "bg-emerald-50 text-emerald-600 font-semibold border-l-[3px] border-emerald-500" + : "text-gray-600 hover:bg-gray-50 border-l-[3px] border-transparent" )} > - {/* active indicator bar */} - {active && ( - - )} - {/* icon */} {item.icon && ( {item.icon} @@ -100,18 +72,16 @@ const NavItemRow = React.memo( )} {/* label */} - {!collapsed && ( - {item.label} - )} + {item.label} {/* badge */} - {!collapsed && item.badge !== undefined && ( + {item.badge !== undefined && ( {item.badge} @@ -123,101 +93,17 @@ const NavItemRow = React.memo( ); NavItemRow.displayName = "NavItemRow"; -// ─── User info footer ────────────────────────────────────────────────────────── - -const UserFooter = ({ - user, - collapsed, -}: { - user: SideNavUser; - collapsed?: boolean; -}) => { - return ( -
- {/* Completion progress bar */} - {!collapsed && user.completionPercent !== undefined && ( -
-
- - {user.completionLabel ?? "Profile Completion"} - - - {user.completionPercent}% - -
-
-
-
-
- )} - - {/* User row */} -
- {/* avatar */} -
- {user.avatar ? ( - {user.name} - ) : ( -
- {user.name.slice(0, 2).toUpperCase()} -
- )} - -
- - {/* user info */} - {!collapsed && ( -
-

{user.name}

- {user.email && ( -

{user.email}

- )} -
- )} - - {/* chevron */} - {!collapsed && ( - - - - )} -
-
- ); -}; - -// ─── Main SideNav ────────────────────────────────────────────────────────────── +// ─── Main SideNav ───────────────────────────────────────────────────────────── const SideNav = React.forwardRef( ( { className, - logo, - brandName = "GEO", + brandName = "GEO Platform", + brandIcon, groups, activeId, onNavClick, - user, - footerExtra, - collapsed = false, - onCollapsedChange, ...props }, ref @@ -226,75 +112,44 @@ const SideNav = React.forwardRef( ); } diff --git a/frontend/components/ui/api-states.tsx b/frontend/components/ui/api-states.tsx new file mode 100644 index 0000000..f7c5c4f --- /dev/null +++ b/frontend/components/ui/api-states.tsx @@ -0,0 +1,137 @@ +"use client"; + +/** + * 统一 API 状态组件 + * - LoadingState: 骨架屏加载状态 + * - ErrorState: 错误展示 + 重试按钮 + * - EmptyState: 空数据状态 + */ + +import { AlertCircle, RefreshCw, Inbox } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Skeleton } from "@/components/ui/skeleton"; + +// ── LoadingState ───────────────────────────────────────────────────────────── + +export interface LoadingStateProps { + /** 骨架行数(默认 3) */ + rows?: number; + /** 是否展示卡片网格布局(默认 false,展示列表) */ + grid?: boolean; + /** 网格列数(grid=true 时生效,默认 3) */ + cols?: 2 | 3 | 4; + /** 自定义高度类名(如 "h-24") */ + rowHeight?: string; +} + +export function LoadingState({ + rows = 3, + grid = false, + cols = 3, + rowHeight = "h-24", +}: LoadingStateProps) { + const colClass = { + 2: "md:grid-cols-2", + 3: "md:grid-cols-2 lg:grid-cols-3", + 4: "md:grid-cols-2 lg:grid-cols-4", + }[cols]; + + if (grid) { + return ( +
+ {Array.from({ length: rows }).map((_, i) => ( + + ))} +
+ ); + } + + return ( +
+ {Array.from({ length: rows }).map((_, i) => ( + + ))} +
+ ); +} + +// ── ErrorState ─────────────────────────────────────────────────────────────── + +export interface ErrorStateProps { + /** 错误对象或错误消息字符串 */ + error: Error | string | null | undefined; + /** 点击重试的回调 */ + onRetry?: () => void; + /** 重试按钮文字(默认"重试") */ + retryLabel?: string; + /** 标题(默认"数据加载失败") */ + title?: string; +} + +export function ErrorState({ + error, + onRetry, + retryLabel = "重试", + title = "数据加载失败", +}: ErrorStateProps) { + const message = + error instanceof Error + ? error.message + : typeof error === "string" + ? error + : "发生未知错误,请稍后重试"; + + return ( +
+ +

{title}

+

{message}

+ {onRetry && ( + + )} +
+ ); +} + +// ── EmptyState ─────────────────────────────────────────────────────────────── + +export interface EmptyStateProps { + /** 主提示文字 */ + message?: string; + /** 次级说明文字 */ + description?: string; + /** 操作按钮(可选) */ + action?: React.ReactNode; + /** 自定义图标 */ + icon?: React.ReactNode; +} + +export function EmptyState({ + message = "暂无数据", + description, + action, + icon, +}: EmptyStateProps) { + return ( +
+
+ {icon ?? } +
+

{message}

+ {description && ( +

+ {description} +

+ )} + {action &&
{action}
} +
+ ); +} diff --git a/frontend/components/ui/button.tsx b/frontend/components/ui/button.tsx index 781a4e1..d9bbcd6 100644 --- a/frontend/components/ui/button.tsx +++ b/frontend/components/ui/button.tsx @@ -10,19 +10,19 @@ const buttonVariants = cva( variants: { variant: { default: - "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow-md hover:-translate-y-px", + "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow-md", destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 hover:shadow-md hover:-translate-y-px", + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 hover:shadow-md", outline: - "border border-border bg-background text-foreground hover:bg-muted hover:border-primary/40 hover:-translate-y-px", + "border border-border bg-background text-foreground hover:bg-muted hover:border-primary/40", secondary: - "bg-muted text-foreground hover:bg-muted/80 hover:-translate-y-px", + "bg-muted text-foreground hover:bg-muted/80", ghost: "text-foreground hover:bg-muted hover:text-foreground", link: "text-primary underline-offset-4 hover:underline p-0 h-auto", accent: - "bg-accent text-accent-foreground shadow-sm hover:bg-accent/90 hover:shadow-md hover:-translate-y-px", + "bg-accent text-accent-foreground shadow-sm hover:bg-accent/90 hover:shadow-md", }, size: { default: "h-10 px-5 py-2.5", diff --git a/frontend/components/ui/card.tsx b/frontend/components/ui/card.tsx index e2501f3..8cfdd2b 100644 --- a/frontend/components/ui/card.tsx +++ b/frontend/components/ui/card.tsx @@ -8,9 +8,9 @@ const cardVariants = cva( { variants: { variant: { - default: "shadow-card hover:shadow-card-hover hover:-translate-y-0.5", + default: "shadow-sm hover:shadow-card-hover hover:border-primary/30", flat: "shadow-none", - elevated: "shadow-md hover:shadow-hover hover:-translate-y-1", + elevated: "shadow-md hover:shadow-lg hover:border-primary/30", ghost: "border-transparent shadow-none bg-transparent", }, padding: { diff --git a/frontend/components/ui/notification-container.tsx b/frontend/components/ui/notification-container.tsx new file mode 100644 index 0000000..f3865a4 --- /dev/null +++ b/frontend/components/ui/notification-container.tsx @@ -0,0 +1,90 @@ +/** + * 全局 Toast/通知 UI 组件 + * + * 从 notification-store 读取通知队列,渲染为浮动通知列表。 + * 放置在 layout 层级,自动显示/消失。 + */ + +"use client"; + +import { X, CheckCircle, AlertTriangle, Info, AlertCircle } from "lucide-react"; +import { useNotificationStore } from "@/lib/stores/notification-store"; +import type { Notification, NotificationType } from "@/lib/stores/notification-store"; +import { cn } from "@/lib/utils"; + +// ── 图标映射 ──────────────────────────────────────────────────────────── + +const ICON_BY_TYPE: Record = { + success: , + error: , + warning: , + info: , +}; + +// ── 样式映射 ──────────────────────────────────────────────────────────── + +const STYLE_BY_TYPE: Record = { + success: "border-emerald-200 bg-emerald-50 text-emerald-800", + error: "border-red-200 bg-red-50 text-red-800", + warning: "border-amber-200 bg-amber-50 text-amber-800", + info: "border-blue-200 bg-blue-50 text-blue-800", +}; + +// ── 单条通知 ──────────────────────────────────────────────────────────── + +function NotificationItem({ + notification, + onRemove, +}: { + notification: Notification; + onRemove: (id: string) => void; +}) { + return ( +
+
{ICON_BY_TYPE[notification.type]}
+
+ {notification.title && ( +

+ {notification.title} +

+ )} +

{notification.message}

+
+ +
+ ); +} + +// ── 通知容器 ──────────────────────────────────────────────────────────── + +export function NotificationContainer() { + const notifications = useNotificationStore((s) => s.notifications); + const removeNotification = useNotificationStore((s) => s.removeNotification); + + if (notifications.length === 0) return null; + + return ( +
+ {notifications.map((notification) => ( +
+ +
+ ))} +
+ ); +} \ No newline at end of file diff --git a/frontend/e2e/tests/login-redirect-system-chrome.spec.ts b/frontend/e2e/tests/login-redirect-system-chrome.spec.ts new file mode 100644 index 0000000..90b14f8 --- /dev/null +++ b/frontend/e2e/tests/login-redirect-system-chrome.spec.ts @@ -0,0 +1,27 @@ +import { test, expect, chromium } from "@playwright/test"; + +const TEST_USER = { + email: "admin@fischer.com", + password: "Admin@123", +}; + +test.use({ + launchOptions: { + executablePath: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + }, +}); + +test.describe("登录跳转测试(系统Chrome)", () => { + test("登录成功后应跳转到dashboard并保持在dashboard", async ({ page }) => { + await page.goto("/login"); + + await page.locator("#email").fill(TEST_USER.email); + await page.locator("#password").fill(TEST_USER.password); + await page.getByRole("button", { name: /登录/ }).click(); + + await expect(page).toHaveURL(/\/dashboard/, { timeout: 15000 }); + await page.waitForTimeout(3000); + await expect(page).toHaveURL(/\/dashboard/); + await expect(page.getByText("Overview", { exact: false })).toBeVisible({ timeout: 10000 }); + }); +}); diff --git a/frontend/e2e/tests/login-redirect.spec.ts b/frontend/e2e/tests/login-redirect.spec.ts new file mode 100644 index 0000000..304e6e1 --- /dev/null +++ b/frontend/e2e/tests/login-redirect.spec.ts @@ -0,0 +1,53 @@ +import { test, expect } from "@playwright/test"; + +const TEST_USER = { + email: "admin@fischer.com", + password: "Admin@123", +}; + +test.describe("登录跳转测试", () => { + test("登录成功后应跳转到dashboard并保持在dashboard", async ({ page }) => { + await page.goto("/login"); + + // 填写登录表单 + await page.locator("#email").fill(TEST_USER.email); + await page.locator("#password").fill(TEST_USER.password); + await page.getByRole("button", { name: /登录/ }).click(); + + // 等待导航到dashboard + await expect(page).toHaveURL(/\/dashboard/, { timeout: 15000 }); + + // 等待页面稳定,确保没有跳回login + await page.waitForTimeout(3000); + await expect(page).toHaveURL(/\/dashboard/); + + // 验证dashboard内容可见 + await expect(page.getByText("Overview", { exact: false })).toBeVisible({ timeout: 10000 }); + }); + + test("登录后应能访问所有dashboard子页面", async ({ page }) => { + await page.goto("/login"); + + await page.locator("#email").fill(TEST_USER.email); + await page.locator("#password").fill(TEST_USER.password); + await page.getByRole("button", { name: /登录/ }).click(); + + await expect(page).toHaveURL(/\/dashboard/, { timeout: 15000 }); + + // 测试各个子页面 + const pages = [ + "/dashboard/analytics", + "/dashboard/knowledge", + "/dashboard/content", + "/dashboard/distribution", + ]; + + for (const url of pages) { + await page.goto(url); + await expect(page).toHaveURL(url, { timeout: 10000 }); + // 确保没有跳回login + await page.waitForTimeout(1000); + await expect(page).not.toHaveURL(/\/login/); + } + }); +}); diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index 06c8019..a278e39 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -22,6 +22,10 @@ export { contentGenerationApi, distributionApi, analyticsApi, + alertsApi, + brandsApi, + suggestionsApi, + onboardingApi, } from "./api/index"; export type { diff --git a/frontend/lib/api/admin.ts b/frontend/lib/api/admin.ts index 5622be3..4b82b7a 100644 --- a/frontend/lib/api/admin.ts +++ b/frontend/lib/api/admin.ts @@ -1,8 +1,37 @@ import { fetchWithAuth } from "./client"; +export interface AdminStatsData { + total_users: number; + total_queries: number; + total_citations: number; + citation_rate: number; + today_active_users: number; +} + +export interface AdminUser { + id: string; + email: string; + name: string | null; + plan: string; + is_active: boolean; + is_admin: boolean; + email_verified: boolean; + query_count: number; + created_at: string; +} + +export interface AdminUserListResponse { + items: AdminUser[]; + total: number; +} + +export interface AdminActionResponse { + message: string; +} + export const adminApi = { getStats: async (token: string) => - fetchWithAuth("/api/v1/admin/stats", {}, token), + fetchWithAuth("/api/v1/admin/stats", {}, token) as Promise, getUsers: async ( token: string, params?: { skip?: number; limit?: number; search?: string } @@ -15,16 +44,16 @@ export const adminApi = { ) as [string, string][] ).toString() : ""; - return fetchWithAuth(`/api/v1/admin/users${query}`, {}, token); + return fetchWithAuth(`/api/v1/admin/users${query}`, {}, token) as Promise; }, getUserDetail: async (token: string, userId: string) => - fetchWithAuth(`/api/v1/admin/users/${userId}`, {}, token), + fetchWithAuth(`/api/v1/admin/users/${userId}`, {}, token) as Promise, toggleUserActive: async (token: string, userId: string) => fetchWithAuth( `/api/v1/admin/users/${userId}/toggle-active`, { method: "POST" }, token - ), + ) as Promise, updateUserPlan: async (token: string, userId: string, plan: string) => fetchWithAuth( `/api/v1/admin/users/${userId}/update-plan`, @@ -33,5 +62,5 @@ export const adminApi = { body: JSON.stringify({ plan }), }, token - ), + ) as Promise, }; diff --git a/frontend/lib/api/alerts.ts b/frontend/lib/api/alerts.ts new file mode 100644 index 0000000..ceddfe9 --- /dev/null +++ b/frontend/lib/api/alerts.ts @@ -0,0 +1,49 @@ +import { fetchWithAuth } from "./client"; + +function buildQuery(params: Record): string { + const qs = Object.entries(params) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`) + .join("&"); + return qs ? `?${qs}` : ""; +} + +export const alertsApi = { + /** 获取未读告警数量 */ + getUnreadCount: (token: string) => + fetchWithAuth("/api/v1/alerts/unread-count", {}, token), + + /** 获取告警列表 */ + getAlerts: ( + token: string, + params?: { limit?: number; offset?: number; is_read?: boolean } + ) => fetchWithAuth(`/api/v1/alerts/${buildQuery(params || {})}`, {}, token), + + /** 标记单条告警已读 */ + markRead: (token: string, alertId: string) => + fetchWithAuth(`/api/v1/alerts/${alertId}/read`, { method: "POST" }, token), + + /** 标记所有告警已读 */ + markAllRead: (token: string) => + fetchWithAuth("/api/v1/alerts/read-all", { method: "POST" }, token), + + /** 获取告警设置 */ + getSettings: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/alerts/settings?brand_id=${encodeURIComponent(brandId)}`, {}, token), + + /** 更新告警设置 */ + updateSettings: ( + token: string, + data: Array<{ + brand_id: string; + alert_type: string; + enabled: boolean; + threshold?: number; + }> + ) => + fetchWithAuth( + "/api/v1/alerts/settings", + { method: "PUT", body: JSON.stringify(data) }, + token + ), +}; diff --git a/frontend/lib/api/brands.ts b/frontend/lib/api/brands.ts new file mode 100644 index 0000000..d1f1c69 --- /dev/null +++ b/frontend/lib/api/brands.ts @@ -0,0 +1,89 @@ +import { fetchWithAuth } from "./client"; + +export interface CreateBrandPayload { + name: string; + aliases?: string[]; + website?: string | null; + industry?: string | null; + platforms?: string[]; + frequency?: string; +} + +export interface UpdateBrandPayload { + name?: string; + aliases?: string[]; + website?: string | null; + industry?: string | null; + platforms?: string[]; + frequency?: string; + status?: string; +} + +export interface AddCompetitorPayload { + competitor_brand_id?: string; + competitor_name?: string; + name?: string; + aliases?: string[]; +} + +function buildQuery(params: Record): string { + const qs = Object.entries(params) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`) + .join("&"); + return qs ? `?${qs}` : ""; +} + +export const brandsApi = { + /** 获取品牌列表 */ + list: (token: string, params?: { limit?: number; offset?: number }) => + fetchWithAuth(`/api/v1/brands/${buildQuery(params || {})}`, {}, token), + + /** 创建品牌 */ + create: (token: string, data: CreateBrandPayload) => + fetchWithAuth("/api/v1/brands/", { method: "POST", body: JSON.stringify(data) }, token), + + /** 更新品牌 */ + update: (token: string, brandId: string, data: UpdateBrandPayload) => + fetchWithAuth( + `/api/v1/brands/${brandId}`, + { method: "PUT", body: JSON.stringify(data) }, + token + ), + + /** 删除品牌 */ + delete: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/brands/${brandId}`, { method: "DELETE" }, token), + + /** 获取品牌详情 */ + getDetail: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/brands/${brandId}`, {}, token), + + /** 立即查询品牌 */ + queryNow: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/brands/${brandId}/query-now`, { method: "POST" }, token), + + /** 添加竞品 */ + addCompetitor: (token: string, brandId: string, data: AddCompetitorPayload) => + fetchWithAuth( + `/api/v1/brands/${brandId}/competitors`, + { method: "POST", body: JSON.stringify(data) }, + token + ), + + /** 删除竞品 */ + deleteCompetitor: (token: string, brandId: string, competitorId: string) => + fetchWithAuth( + `/api/v1/brands/${brandId}/competitors/${competitorId}`, + { method: "DELETE" }, + token + ), + + /** 获取竞品推荐 */ + getCompetitorRecommendations: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/brands/${brandId}/competitor-recommendations`, {}, token), + + /** 获取品牌对比数据 */ + getCompare: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/brands/${brandId}/compare`, {}, token), +}; diff --git a/frontend/lib/api/citations.ts b/frontend/lib/api/citations.ts index 499be34..e7b7c3f 100644 --- a/frontend/lib/api/citations.ts +++ b/frontend/lib/api/citations.ts @@ -1,12 +1,37 @@ import { fetchWithAuth } from "./client"; +export interface CitationRecord { + id: string; + query_id: string; + platform: string; + cited: boolean; + citation_position: number | null; + citation_text: string | null; + competitor_brands: string[]; + confidence: number | null; + match_type: string | null; + queried_at: string; +} + +export interface CitationListResponse { + items: CitationRecord[]; + total: number; +} + +export interface CitationStats { + total_queries: number; + total_citations: number; + citation_rate: number; + avg_position: number | null; +} + export const citationsApi = { list: (token: string, params?: string) => fetchWithAuth( `/api/v1/citations/${params ? `?${params}` : ""}`, {}, token - ), + ) as Promise, getStats: (token: string) => - fetchWithAuth("/api/v1/citations/stats/", {}, token), + fetchWithAuth("/api/v1/citations/stats/", {}, token) as Promise, }; diff --git a/frontend/lib/api/client.ts b/frontend/lib/api/client.ts index 3fcef2c..d214045 100644 --- a/frontend/lib/api/client.ts +++ b/frontend/lib/api/client.ts @@ -1,3 +1,6 @@ +import { getSession } from "next-auth/react"; +import type { Session } from "next-auth"; + export const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; export function getApiUrl(path: string): string { @@ -9,19 +12,28 @@ export async function fetchWithAuth( options: RequestInit = {}, token?: string ) { + // 如果没有显式传入 token,尝试从 NextAuth session 获取 + let authToken = token; + if (!authToken && typeof window !== "undefined") { + try { + const session = await getSession(); + authToken = (session as Session)?.accessToken; + } catch { + // ignore session fetch error + } + } + const headers: Record = { "Content-Type": "application/json", ...((options.headers as Record) || {}), }; - if (token) { - headers["Authorization"] = `Bearer ${token}`; + if (authToken) { + headers["Authorization"] = `Bearer ${authToken}`; } const res = await fetch(`${API_BASE}${url}`, { ...options, headers }); if (res.status === 401) { - if (typeof window !== "undefined") { - window.location.href = "/login"; - } + // 不要自动跳转登录页,让页面组件/layout自行处理认证状态 throw new Error("登录已过期,请重新登录"); } diff --git a/frontend/lib/api/index.ts b/frontend/lib/api/index.ts index 02dad56..134db9c 100644 --- a/frontend/lib/api/index.ts +++ b/frontend/lib/api/index.ts @@ -4,10 +4,13 @@ export { fetchWithAuth, getApiUrl, API_BASE } from "./client"; // ── 各模块 API ───────────────────────────────────────────────────────────────── export { authApi } from "./auth"; export { queriesApi } from "./queries"; +export type { ApiQueryItem, QueryListResponse, CreateQueryPayload, UpdateQueryPayload } from "./queries"; export { citationsApi } from "./citations"; +export type { CitationRecord, CitationListResponse, CitationStats } from "./citations"; export { reportsApi } from "./reports"; export { subscriptionsApi } from "./subscriptions"; export { adminApi } from "./admin"; +export type { AdminStatsData, AdminUser, AdminUserListResponse, AdminActionResponse } from "./admin"; export { agentsApi } from "./agents"; export { lifecycleApi } from "./lifecycle"; export { contentsApi } from "./contents"; @@ -16,6 +19,11 @@ export { knowledgeApi } from "./knowledge"; export { contentGenerationApi } from "./content"; export { distributionApi } from "./distribution"; export { analyticsApi } from "./analytics"; +export { alertsApi } from "./alerts"; +export { brandsApi } from "./brands"; +export type { CreateBrandPayload, UpdateBrandPayload, AddCompetitorPayload } from "./brands"; +export { suggestionsApi } from "./suggestions"; +export { onboardingApi } from "./onboarding"; // ── 类型导出 ─────────────────────────────────────────────────────────────────── export type { Agent, AgentRunLog } from "./agents"; @@ -93,6 +101,10 @@ import { knowledgeApi } from "./knowledge"; import { contentGenerationApi } from "./content"; import { distributionApi } from "./distribution"; import { analyticsApi } from "./analytics"; +import { alertsApi } from "./alerts"; +import { brandsApi } from "./brands"; +import { suggestionsApi } from "./suggestions"; +import { onboardingApi } from "./onboarding"; /** * 聚合 API 对象,保持与原 `import { api } from "@/lib/api"` 的向后兼容。 @@ -113,4 +125,8 @@ export const api = { contentGeneration: contentGenerationApi, distribution: distributionApi, analytics: analyticsApi, + alerts: alertsApi, + brands: brandsApi, + suggestions: suggestionsApi, + onboarding: onboardingApi, }; diff --git a/frontend/lib/api/knowledge.ts b/frontend/lib/api/knowledge.ts index 0fa3413..c004a28 100644 --- a/frontend/lib/api/knowledge.ts +++ b/frontend/lib/api/knowledge.ts @@ -29,7 +29,7 @@ export interface SearchResult { score: number; document_id: string; document_title: string; - metadata: Record; + metadata: Record; } export interface SearchResponse { diff --git a/frontend/lib/api/onboarding.ts b/frontend/lib/api/onboarding.ts new file mode 100644 index 0000000..4d36686 --- /dev/null +++ b/frontend/lib/api/onboarding.ts @@ -0,0 +1,47 @@ +import { fetchWithAuth } from "./client"; + +export const onboardingApi = { + /** 检查引导状态 */ + checkOnboardingStatus: (token: string) => + fetchWithAuth("/api/v1/onboarding/status", {}, token), + + /** 创建引导品牌 */ + createOnboardingBrand: ( + token: string, + data: { + name: string; + competitors: string[]; + platforms: string[]; + frequency: "daily" | "weekly" | "monthly"; + } + ) => + fetchWithAuth( + "/api/v1/onboarding/brand", + { method: "POST", body: JSON.stringify(data) }, + token + ), + + /** 获取竞品推荐 */ + getCompetitorRecommendations: (token: string, brandName: string) => + fetchWithAuth( + `/api/v1/onboarding/competitor-recommendations?brand_name=${encodeURIComponent(brandName)}`, + {}, + token + ), + + /** 获取健康报告 */ + getHealthReport: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/onboarding/health-report/${brandId}`, {}, token), + + /** 获取行动建议 */ + getActionSuggestions: (token: string, brandId: string) => + fetchWithAuth(`/api/v1/onboarding/action-suggestions/${brandId}`, {}, token), + + /** 完成引导 */ + completeOnboarding: (token: string, brandId: string) => + fetchWithAuth( + `/api/v1/onboarding/complete/${brandId}`, + { method: "POST" }, + token + ), +}; diff --git a/frontend/lib/api/queries.ts b/frontend/lib/api/queries.ts index 5e2fabf..256b81f 100644 --- a/frontend/lib/api/queries.ts +++ b/frontend/lib/api/queries.ts @@ -1,19 +1,52 @@ import { fetchWithAuth } from "./client"; +export interface CreateQueryPayload { + keyword: string; + brand_id?: string; + platforms?: string[]; + frequency?: string; +} + +export interface UpdateQueryPayload { + keyword?: string; + platforms?: string[]; + frequency?: string; + is_active?: boolean; +} + +export interface ApiQueryItem { + id: string; + keyword: string; + target_brand: string; + brand_id?: string; + brand_aliases?: string[]; + platforms: string[]; + frequency: string; + is_active: boolean; + status: string; + last_queried_at: string | null; + created_at: string; +} + +export interface QueryListResponse { + items: ApiQueryItem[]; + total: number; +} + export const queriesApi = { - list: (token: string) => fetchWithAuth("/api/v1/queries/", {}, token), - create: (token: string, data: unknown) => + list: (token: string) => fetchWithAuth("/api/v1/queries/", {}, token) as Promise, + create: (token: string, data: CreateQueryPayload) => fetchWithAuth( "/api/v1/queries/", { method: "POST", body: JSON.stringify(data) }, token - ), - update: (token: string, id: string, data: unknown) => + ) as Promise, + update: (token: string, id: string, data: UpdateQueryPayload) => fetchWithAuth( `/api/v1/queries/${id}`, { method: "PUT", body: JSON.stringify(data) }, token - ), + ) as Promise, delete: (token: string, id: string) => fetchWithAuth(`/api/v1/queries/${id}`, { method: "DELETE" }, token), runNow: (token: string, id: string) => diff --git a/frontend/lib/api/suggestions.ts b/frontend/lib/api/suggestions.ts new file mode 100644 index 0000000..1fedf05 --- /dev/null +++ b/frontend/lib/api/suggestions.ts @@ -0,0 +1,44 @@ +import { fetchWithAuth } from "./client"; + +function buildQuery(params: Record): string { + const qs = Object.entries(params) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`) + .join("&"); + return qs ? `?${qs}` : ""; +} + +export const suggestionsApi = { + /** 获取建议列表 */ + getSuggestions: ( + token: string, + brandId: string, + params?: Record + ) => + fetchWithAuth( + `/api/v1/suggestions/${brandId}${buildQuery(params || {})}`, + {}, + token + ), + + /** 重新生成建议 */ + regenerateSuggestions: (token: string, brandId: string) => + fetchWithAuth( + `/api/v1/suggestions/${brandId}/regenerate`, + { method: "POST" }, + token + ), + + /** 更新建议状态 */ + updateSuggestionStatus: ( + token: string, + brandId: string, + suggestionId: string, + status: string + ) => + fetchWithAuth( + `/api/v1/suggestions/${brandId}/${suggestionId}/status`, + { method: "PUT", body: JSON.stringify({ status }) }, + token + ), +}; diff --git a/frontend/lib/auth.ts b/frontend/lib/auth.ts index dd44123..a12ed6c 100644 --- a/frontend/lib/auth.ts +++ b/frontend/lib/auth.ts @@ -2,6 +2,38 @@ import { NextAuthOptions } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import { api } from "@/lib/api"; +/** 尝试使用 refresh token 获取新的 access token */ +async function refreshAccessToken(token: Record) { + try { + const backendUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; + const res = await fetch(`${backendUrl}/api/v1/auth/refresh`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ refresh_token: token.refreshToken }), + }); + + if (!res.ok) { + throw new Error(`Refresh failed: ${res.status}`); + } + + const data = await res.json(); + return { + ...token, + accessToken: data.access_token, + refreshToken: data.refresh_token, // 滑动过期:更新为新 refresh token + // 新 access token 有效期 1 小时 + expires_at: Date.now() + 60 * 60 * 1000, + error: undefined, + }; + } catch (error) { + // 刷新失败:标记错误,让前端展示重新登录 + return { + ...token, + error: "RefreshAccessTokenError", + }; + } +} + export const authOptions: NextAuthOptions = { providers: [ CredentialsProvider({ @@ -11,9 +43,7 @@ export const authOptions: NextAuthOptions = { password: { label: "密码", type: "password" }, }, async authorize(credentials) { - console.log("[NextAuth] authorize called with email:", credentials?.email); if (!credentials?.email || !credentials?.password) { - console.log("[NextAuth] missing credentials"); return null; } try { @@ -21,27 +51,19 @@ export const authOptions: NextAuthOptions = { email: credentials.email, password: credentials.password, }); - console.log("[NextAuth] login response:", JSON.stringify({ - hasAccessToken: !!res.access_token, - userId: res.user?.id, - userEmail: res.user?.email, - isAdmin: res.user?.is_admin, - })); if (res.access_token) { const user = { id: res.user?.id || credentials.email, name: res.user?.name, email: res.user?.email, accessToken: res.access_token, + refreshToken: res.refresh_token, is_admin: res.user?.is_admin || false, }; - console.log("[NextAuth] returning user:", JSON.stringify(user)); return user; } - console.log("[NextAuth] no access_token in response"); return null; } catch (error) { - console.error("[NextAuth] authorize error:", error); return null; } }, @@ -52,17 +74,35 @@ export const authOptions: NextAuthOptions = { }, callbacks: { async jwt({ token, user }) { + // 初次登录:将用户信息写入 token if (user) { + token.sub = user.id; token.accessToken = user.accessToken; + token.refreshToken = (user as unknown as Record).refreshToken as string; token.id = user.id; - token.is_admin = user.is_admin; + token.is_admin = (user as unknown as Record).is_admin as boolean; + // access token 有效期 1 小时 + token.expires_at = Date.now() + 60 * 60 * 1000; + return token; } + + // 后续请求:检查 access token 是否即将过期(提前 5 分钟刷新) + const expiresAt = token.expires_at as number | undefined; + if (expiresAt && expiresAt < Date.now() + 5 * 60 * 1000) { + return refreshAccessToken(token as Record); + } + return token; }, async session({ session, token }) { session.accessToken = token.accessToken as string; - session.user.id = token.id as string; - session.user.is_admin = token.is_admin as boolean; + session.refreshToken = token.refreshToken as string; + // 将 refresh 失败错误传递给前端,以便触发重新登录 + session.error = token.error as string | undefined; + if (session.user) { + session.user.id = token.id as string; + session.user.is_admin = token.is_admin as boolean; + } return session; }, }, diff --git a/frontend/lib/hooks/use-api.ts b/frontend/lib/hooks/use-api.ts new file mode 100644 index 0000000..be72d41 --- /dev/null +++ b/frontend/lib/hooks/use-api.ts @@ -0,0 +1,171 @@ +/** + * 通用 SWR Hooks + * 封装 useSWR + fetchWithAuth,统一处理加载/错误/重试逻辑 + */ + +import useSWR, { type SWRConfiguration, type KeyedMutator } from "swr"; +import { useCallback, useState } from "react"; +import { fetchWithAuth } from "@/lib/api/client"; + +// ── 类型定义 ──────────────────────────────────────────────────────────────────── + +export interface UseApiReturn { + data: T | undefined; + isLoading: boolean; + error: Error | undefined; + mutate: KeyedMutator; + /** 手动重新获取数据 */ + refresh: () => void; +} + +export interface UsePaginatedApiReturn extends UseApiReturn { + total: number; + page: number; + pageSize: number; + setPage: (page: number) => void; +} + +export interface UseApiMutationReturn { + trigger: (body?: B) => Promise; + isMutating: boolean; + error: Error | undefined; + reset: () => void; +} + +// ── SWR 全局 Fetcher ───────────────────────────────────────────────────────── + +/** + * 基于 fetchWithAuth 的 SWR fetcher + * key 格式:url string 或 [url, token] + */ +export async function swrFetcher(url: string): Promise { + return fetchWithAuth(url) as Promise; +} + +// ── 主 Hook ────────────────────────────────────────────────────────────────── + +/** + * 基础数据获取 Hook + * @param url API 路径(null 时暂停请求) + * @param options SWR 配置项 + */ +export function useApi( + url: string | null, + options?: SWRConfiguration +): UseApiReturn { + const { data, error, isLoading, mutate } = useSWR( + url, + swrFetcher, + { + revalidateOnFocus: false, + shouldRetryOnError: true, + errorRetryCount: 2, + errorRetryInterval: 3000, + ...options, + } + ); + + const refresh = useCallback(() => { + mutate(); + }, [mutate]); + + return { + data, + isLoading, + error: error as Error | undefined, + mutate, + refresh, + }; +} + +// ── 分页 Hook ──────────────────────────────────────────────────────────────── + +export interface PaginatedResponse { + items: T[]; + total: number; +} + +/** + * 支持分页的数据获取 Hook + * @param baseUrl 基础 API 路径(不含分页参数) + * @param params 分页参数 + */ +export function usePaginatedApi( + baseUrl: string | null, + params: { page: number; pageSize: number } +): UsePaginatedApiReturn { + const [page, setPage] = useState(params.page); + const { pageSize } = params; + + const url = baseUrl + ? `${baseUrl}?limit=${pageSize}&offset=${(page - 1) * pageSize}` + : null; + + const { data, error, isLoading, mutate } = useSWR>( + url, + swrFetcher>, + { + revalidateOnFocus: false, + shouldRetryOnError: true, + errorRetryCount: 2, + } + ); + + const refresh = useCallback(() => { + mutate(); + }, [mutate]); + + return { + data: data?.items, + total: data?.total ?? 0, + isLoading, + error: error as Error | undefined, + mutate: mutate as unknown as KeyedMutator, + refresh, + page, + pageSize, + setPage, + }; +} + +// ── Mutation Hook ──────────────────────────────────────────────────────────── + +/** + * API 数据变更 Hook(POST / PUT / DELETE) + * @param url API 路径 + * @param method HTTP 方法(默认 POST) + */ +export function useApiMutation( + url: string, + method: string = "POST" +): UseApiMutationReturn { + const [isMutating, setIsMutating] = useState(false); + const [error, setError] = useState(undefined); + + const trigger = useCallback( + async (body?: B): Promise => { + try { + setIsMutating(true); + setError(undefined); + const result = await fetchWithAuth(url, { + method, + body: body !== undefined ? JSON.stringify(body) : undefined, + }) as T; + return result; + } catch (err) { + const e = err instanceof Error ? err : new Error(String(err)); + setError(e); + return null; + } finally { + setIsMutating(false); + } + }, + [url, method] + ); + + const reset = useCallback(() => { + setError(undefined); + }, []); + + return { trigger, isMutating, error, reset }; +} diff --git a/frontend/lib/stores/brand-store.ts b/frontend/lib/stores/brand-store.ts new file mode 100644 index 0000000..1ea70ce --- /dev/null +++ b/frontend/lib/stores/brand-store.ts @@ -0,0 +1,306 @@ +/** + * 品牌全局状态 Store (Zustand) + * + * 与 SWR 互补: + * - SWR 管理服务端缓存(品牌列表数据获取、缓存、重验证) + * - 此 Store 管理客户端侧状态: + * 1. 当前选中品牌(跨页面共享) + * 2. 乐观更新(操作先更新本地,API 失败再回滚) + * 3. 品牌列表的本地增删(配合 SWR mutate) + */ + +import { create } from "zustand"; +import { fetchWithAuth } from "@/lib/api/client"; +import { brandsApi } from "@/lib/api/brands"; +import type { + BrandListItem, + BrandListResponse, +} from "@/types/brand"; +import type { CreateBrandPayload, UpdateBrandPayload } from "@/lib/api/brands"; +import { useNotificationStore } from "./notification-store"; + +// ── 类型定义 ──────────────────────────────────────────────────────────────────── + +export interface BrandState { + /** 当前选中品牌 ID */ + selectedBrandId: string | null; + /** 当前选中品牌名称(方便 UI 直接显示) */ + selectedBrandName: string | null; + /** 品牌列表本地副本(用于乐观更新时的临时状态) */ + localBrands: BrandListItem[]; + /** 正在进行乐观更新的操作类型 */ + optimisticAction: "creating" | "updating" | "deleting" | null; +} + +export interface BrandActions { + /** 选中品牌 */ + selectBrand: (brandId: string, brandName?: string) => void; + /** 清除选中品牌 */ + clearSelection: () => void; + /** 从 SWR 数据同步品牌列表到本地副本 */ + syncFromSWR: (brands: BrandListItem[]) => void; + + // ── 乐观更新操作 ────────────────────────────────────────────────────────── + /** + * 乐观创建品牌: + * 1. 先在本地列表添加临时条目 + * 2. 异步调用 API + * 3. 成功 → 用真实数据替换临时条目(配合 SWR mutate) + * 4. 失败 → 回滚本地列表,显示错误通知 + */ + optimisticCreate: ( + token: string, + payload: CreateBrandPayload, + /** SWR mutate 回调,用于刷新服务端缓存 */ + swrMutate?: () => void, + ) => Promise; + + /** + * 乐观更新品牌: + * 1. 先在本地列表更新条目 + * 2. 异步调用 API + * 3. 成功 → 配合 SWR mutate + * 4. 失败 → 回滚本地列表 + */ + optimisticUpdate: ( + token: string, + brandId: string, + payload: UpdateBrandPayload, + swrMutate?: () => void, + ) => Promise; + + /** + * 乐观删除品牌: + * 1. 先从本地列表移除条目 + * 2. 异步调用 API + * 3. 成功 → 配合 SWR mutate + * 4. 失败 → 恢复本地列表条目 + */ + optimisticDelete: ( + token: string, + brandId: string, + swrMutate?: () => void, + ) => Promise; +} + +// ── 辅助 ──────────────────────────────────────────────────────────────────────── + +/** 生成临时 ID(乐观创建用) */ +function generateTempId(): string { + return `temp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; +} + +// ── 默认值 ────────────────────────────────────────────────────────────────────── + +const INITIAL_STATE: BrandState = { + selectedBrandId: null, + selectedBrandName: null, + localBrands: [], + optimisticAction: null, +}; + +// ── Store ─────────────────────────────────────────────────────────────────────── + +export const useBrandStore = create()((set, get) => ({ + ...INITIAL_STATE, + + selectBrand: (brandId, brandName) => { + set({ + selectedBrandId: brandId, + selectedBrandName: brandName ?? null, + }); + }, + + clearSelection: () => { + set({ selectedBrandId: null, selectedBrandName: null }); + }, + + syncFromSWR: (brands) => { + set({ localBrands: brands }); + }, + + // ── 乐观创建 ──────────────────────────────────────────────────────────── + optimisticCreate: async (token, payload, swrMutate) => { + const { localBrands } = get(); + const notificationStore = useNotificationStore.getState(); + + // 1. 创建临时条目 + const tempBrand: BrandListItem = { + id: generateTempId(), + name: payload.name, + aliases: payload.aliases ?? [], + platforms: payload.platforms ?? [], + frequency: (payload.frequency ?? "weekly") as BrandListItem["frequency"], + status: "pending", + score: null, + last_queried_at: null, + next_query_at: null, + created_at: new Date().toISOString(), + }; + + set({ + localBrands: [...localBrands, tempBrand], + optimisticAction: "creating", + }); + + // 2. 异步调用 API + try { + const created = await brandsApi.create(token, payload as CreateBrandPayload) as BrandListItem; + + // 3. 成功 → 用真实数据替换临时条目 + set((state) => ({ + localBrands: state.localBrands.map((b) => + b.id === tempBrand.id ? created : b + ), + optimisticAction: null, + })); + + notificationStore.addNotification({ + type: "success", + message: `品牌「${created.name}」创建成功`, + }); + + // 触发 SWR 重新获取,保证服务端缓存同步 + swrMutate?.(); + + return created; + } catch (err) { + // 4. 失败 → 回滚 + set((state) => ({ + localBrands: state.localBrands.filter((b) => b.id !== tempBrand.id), + optimisticAction: null, + })); + + const message = err instanceof Error ? err.message : "创建品牌失败"; + notificationStore.addNotification({ type: "error", message }); + + return null; + } + }, + + // ── 乐观更新 ──────────────────────────────────────────────────────────── + optimisticUpdate: async (token, brandId, payload, swrMutate) => { + const { localBrands } = get(); + const notificationStore = useNotificationStore.getState(); + + // 1. 保存原始数据用于回滚 + const originalBrand = localBrands.find((b) => b.id === brandId); + if (!originalBrand) { + // 本地没有此品牌,无法乐观更新,直接走 API + try { + const updated = await brandsApi.update(token, brandId, payload as UpdateBrandPayload) as BrandListItem; + swrMutate?.(); + return updated; + } catch (err) { + const message = err instanceof Error ? err.message : "更新品牌失败"; + notificationStore.addNotification({ type: "error", message }); + return null; + } + } + + // 2. 乐观更新本地列表 + const optimisticBrand = { + ...originalBrand, + ...payload, + id: brandId, // 确保 ID 不被覆盖 + } as BrandListItem; + + set({ + localBrands: localBrands.map((b) => + b.id === brandId ? optimisticBrand : b + ), + optimisticAction: "updating", + }); + + // 3. 异步调用 API + try { + const updated = await brandsApi.update(token, brandId, payload as UpdateBrandPayload) as BrandListItem; + + set({ + localBrands: get().localBrands.map((b) => + b.id === brandId ? updated : b + ), + optimisticAction: null, + }); + + notificationStore.addNotification({ + type: "success", + message: `品牌「${updated.name}」更新成功`, + }); + + swrMutate?.(); + + return updated; + } catch (err) { + // 4. 失败 → 回滚到原始数据 + set((state) => ({ + localBrands: state.localBrands.map((b) => + b.id === brandId ? originalBrand : b + ), + optimisticAction: null, + })); + + const message = err instanceof Error ? err.message : "更新品牌失败"; + notificationStore.addNotification({ type: "error", message }); + + return null; + } + }, + + // ── 乐观删除 ──────────────────────────────────────────────────────────── + optimisticDelete: async (token, brandId, swrMutate) => { + const { localBrands, selectedBrandId } = get(); + const notificationStore = useNotificationStore.getState(); + + // 1. 保存原始数据用于回滚 + const originalBrand = localBrands.find((b) => b.id === brandId); + if (!originalBrand) { + // 本地没有此品牌,直接走 API + try { + await brandsApi.delete(token, brandId); + swrMutate?.(); + return true; + } catch (err) { + const message = err instanceof Error ? err.message : "删除品牌失败"; + notificationStore.addNotification({ type: "error", message }); + return false; + } + } + + // 2. 乐观删除:从本地列表移除 + set({ + localBrands: localBrands.filter((b) => b.id !== brandId), + optimisticAction: "deleting", + // 如果删除的是当前选中品牌,清除选择 + selectedBrandId: selectedBrandId === brandId ? null : selectedBrandId, + selectedBrandName: selectedBrandId === brandId ? null : get().selectedBrandName, + }); + + // 3. 异步调用 API + try { + await brandsApi.delete(token, brandId); + + set({ optimisticAction: null }); + + notificationStore.addNotification({ + type: "success", + message: `品牌「${originalBrand.name}」已删除`, + }); + + swrMutate?.(); + + return true; + } catch (err) { + // 4. 失败 → 恢复原始条目 + set((state) => ({ + localBrands: [...state.localBrands, originalBrand], + optimisticAction: null, + })); + + const message = err instanceof Error ? err.message : "删除品牌失败"; + notificationStore.addNotification({ type: "error", message }); + + return false; + } + }, +})); \ No newline at end of file diff --git a/frontend/lib/stores/index.ts b/frontend/lib/stores/index.ts new file mode 100644 index 0000000..83ba7bc --- /dev/null +++ b/frontend/lib/stores/index.ts @@ -0,0 +1,30 @@ +/** + * Zustand Stores 统一导出 + * + * 使用方式: + * import { useUserStore, useBrandStore, useNotificationStore } from "@/lib/stores"; + */ + +// ── Stores ────────────────────────────────────────────────────────────────── +export { useUserStore } from "./user-store"; +export { useBrandStore } from "./brand-store"; +export { useNotificationStore } from "./notification-store"; + +// ── 类型导出 ──────────────────────────────────────────────────────────────── +export type { + UserPreferences, + UserState, + UserActions, +} from "./user-store"; + +export type { + BrandState, + BrandActions, +} from "./brand-store"; + +export type { + Notification, + NotificationType, + NotificationState, + NotificationActions, +} from "./notification-store"; \ No newline at end of file diff --git a/frontend/lib/stores/notification-store.ts b/frontend/lib/stores/notification-store.ts new file mode 100644 index 0000000..4f400ec --- /dev/null +++ b/frontend/lib/stores/notification-store.ts @@ -0,0 +1,134 @@ +/** + * 全局通知/Toast 状态 Store (Zustand) + * + * 管理应用全局的 toast / 通知队列: + * - 添加通知(支持 success / error / warning / info) + * - 自动过期清除 + * - 手动移除 + */ + +import { create } from "zustand"; + +// ── 类型定义 ──────────────────────────────────────────────────────────── + +export type NotificationType = "success" | "error" | "warning" | "info"; + +export interface Notification { + /** 通知唯一 ID */ + id: string; + /** 通知类型 */ + type: NotificationType; + /** 通知消息 */ + message: string; + /** 通知标题(可选) */ + title?: string; + /** 创建时间戳 */ + createdAt: number; + /** 自动过期时间(毫秒),null 表示不自动过期 */ + duration: number | null; +} + +export interface NotificationState { + /** 当前通知队列 */ + notifications: Notification[]; +} + +export interface NotificationActions { + /** 添加一条通知 */ + addNotification: (payload: { + type: NotificationType; + message: string; + title?: string; + /** 自定义过期时间(毫秒),默认按 type 自动设置 */ + duration?: number | null; + }) => string; + + /** 移除一条通知 */ + removeNotification: (id: string) => void; + + /** 清空所有通知 */ + clearAll: () => void; +} + +// ── 默认过期时间 ──────────────────────────────────────────────────────── + +const DEFAULT_DURATION_BY_TYPE: Record = { + success: 3000, + error: 5000, + warning: 4000, + info: 3000, +}; + +// ── 辅助 ──────────────────────────────────────────────────────────────────── + +/** 生成通知 ID */ +function generateNotificationId(): string { + return `notif-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; +} + +/** 定时器映射,避免重复 */ +const timers = new Map>(); + +// ── 默认值 ────────────────────────────────────────────────────────────────── + +const INITIAL_STATE: NotificationState = { + notifications: [], +}; + +// ── Store ─────────────────────────────────────────────────────────────────── + +export const useNotificationStore = create()( + (set, get) => ({ + ...INITIAL_STATE, + + addNotification: ({ type, message, title, duration }) => { + const id = generateNotificationId(); + const effectiveDuration = duration ?? DEFAULT_DURATION_BY_TYPE[type]; + + const notification: Notification = { + id, + type, + message, + title, + createdAt: Date.now(), + duration: effectiveDuration, + }; + + set((state) => ({ + notifications: [...state.notifications, notification], + })); + + // 设置自动过期 + if (effectiveDuration !== null) { + const timer = setTimeout(() => { + get().removeNotification(id); + timers.delete(id); + }, effectiveDuration); + timers.set(id, timer); + } + + return id; + }, + + removeNotification: (id) => { + // 清除定时器 + const timer = timers.get(id); + if (timer) { + clearTimeout(timer); + timers.delete(id); + } + + set((state) => ({ + notifications: state.notifications.filter((n) => n.id !== id), + })); + }, + + clearAll: () => { + // 清除所有定时器 + timers.forEach((timer) => clearTimeout(timer)); + timers.clear(); + + set({ notifications: [] }); + }, + }) +); \ No newline at end of file diff --git a/frontend/lib/stores/user-store.ts b/frontend/lib/stores/user-store.ts new file mode 100644 index 0000000..674dd2b --- /dev/null +++ b/frontend/lib/stores/user-store.ts @@ -0,0 +1,104 @@ +/** + * 用户全局状态 Store (Zustand) + * + * 与 NextAuth Session 互补: + * - Session 由 next-auth 管理,负责认证流程 + * - 此 Store 管理客户端侧的用户偏好和 UI 状态 + * - 通过 syncFromSession 将 session 数据同步到 store + */ + +import { create } from "zustand"; +import type { Session } from "next-auth"; + +// ── 类型定义 ──────────────────────────────────────────────────────────────────── + +export interface UserPreferences { + /** 侧边栏是否折叠 */ + sidebarCollapsed: boolean; + /** 默认查询频率偏好 */ + defaultFrequency: "daily" | "weekly" | "monthly"; + /** 主题偏好(预留) */ + theme: "light" | "dark" | "system"; +} + +export interface UserState { + /** 当前用户 ID(从 session 同步) */ + userId: string | null; + /** 用户名 */ + userName: string | null; + /** 用户邮箱 */ + userEmail: string | null; + /** 是否管理员 */ + isAdmin: boolean; + /** 是否已认证 */ + isAuthenticated: boolean; + /** 用户偏好设置 */ + preferences: UserPreferences; +} + +export interface UserActions { + /** 从 NextAuth session 同步用户信息 */ + syncFromSession: (session: Session | null) => void; + /** 清除用户状态(登出时调用) */ + clear: () => void; + /** 更新偏好设置(部分更新) */ + updatePreferences: (patch: Partial) => void; + /** 切换侧边栏折叠状态 */ + toggleSidebar: () => void; +} + +// ── 默认值 ────────────────────────────────────────────────────────────────────── + +const DEFAULT_PREFERENCES: UserPreferences = { + sidebarCollapsed: false, + defaultFrequency: "weekly", + theme: "light", +}; + +const INITIAL_STATE: UserState = { + userId: null, + userName: null, + userEmail: null, + isAdmin: false, + isAuthenticated: false, + preferences: DEFAULT_PREFERENCES, +}; + +// ── Store ─────────────────────────────────────────────────────────────────────── + +export const useUserStore = create()((set) => ({ + ...INITIAL_STATE, + + syncFromSession: (session) => { + if (!session || !session.user) { + set(INITIAL_STATE); + return; + } + set({ + userId: session.user.id, + userName: session.user.name ?? null, + userEmail: session.user.email ?? null, + isAdmin: session.user.is_admin ?? false, + isAuthenticated: true, + }); + }, + + clear: () => { + set(INITIAL_STATE); + }, + + updatePreferences: (patch) => { + set((state) => ({ + preferences: { ...state.preferences, ...patch }, + })); + }, + + toggleSidebar: () => { + set((state) => ({ + preferences: { + ...state.preferences, + sidebarCollapsed: !state.preferences.sidebarCollapsed, + }, + })); + }, +})); \ No newline at end of file diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs index 4678774..e25a6a2 100644 --- a/frontend/next.config.mjs +++ b/frontend/next.config.mjs @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: 'standalone', +}; export default nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 812cd8e..7ba922b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,21 +23,36 @@ "react": "^18", "react-dom": "^18", "recharts": "^2.15.4", + "swr": "^2.4.1", "tailwind-merge": "^3.5.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.13" }, "devDependencies": { - "@playwright/test": "^1.59.1", + "@playwright/test": "^1.60.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@vitejs/plugin-react": "^6.0.2", + "@vitest/coverage-v8": "^4.1.7", "eslint": "^8", "eslint-config-next": "14.2.35", + "jsdom": "^29.1.1", "postcss": "^8", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.1.7" } }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -50,6 +65,109 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmmirror.com/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.29.2", "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.2.tgz", @@ -59,6 +177,183 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz", + "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmmirror.com/@emnapi/core/-/core-1.10.0.tgz", @@ -156,6 +451,24 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmmirror.com/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@floating-ui/core": { "version": "1.7.5", "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz", @@ -532,6 +845,16 @@ "node": ">=12.4.0" } }, + "node_modules/@oxc-project/types": { + "version": "0.132.0", + "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@panva/hkdf": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/@panva/hkdf/-/hkdf-1.2.1.tgz", @@ -553,13 +876,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.59.1", - "resolved": "https://registry.npmmirror.com/@playwright/test/-/test-1.59.1.tgz", - "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", + "version": "1.60.0", + "resolved": "https://registry.npmmirror.com/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.59.1" + "playwright": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -1445,6 +1768,289 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1459,6 +2065,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmmirror.com/@swc/counter/-/counter-0.1.3.tgz", @@ -1475,6 +2088,131 @@ "tslib": "^2.4.0" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmmirror.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmmirror.com/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -1486,6 +2224,25 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", @@ -1549,6 +2306,20 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz", @@ -2152,6 +2923,176 @@ "win32" ] }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-v8/-/coverage-v8-4.1.7.tgz", + "integrity": "sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.7", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.7", + "vitest": "4.1.7" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.7.tgz", + "integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.7.tgz", + "integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.7", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", + "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.7.tgz", + "integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.7", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.7.tgz", + "integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.7", + "@vitest/utils": "4.1.7", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.7.tgz", + "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.7.tgz", + "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.7", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz", @@ -2432,6 +3373,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmmirror.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -2439,6 +3390,25 @@ "dev": true, "license": "MIT" }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", @@ -2492,6 +3462,16 @@ "dev": true, "license": "MIT" }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -2627,6 +3607,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", @@ -2743,6 +3733,13 @@ "dev": true, "license": "MIT" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", @@ -2767,6 +3764,27 @@ "node": ">= 8" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", @@ -2913,6 +3931,20 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -2985,6 +4017,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/decimal.js-light": { "version": "2.5.1", "resolved": "https://registry.npmmirror.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz", @@ -3034,6 +4073,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -3065,6 +4123,14 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmmirror.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -3104,6 +4170,19 @@ "dev": true, "license": "MIT" }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.24.2", "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.24.2.tgz", @@ -3220,6 +4299,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -3713,6 +4799,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", @@ -3729,6 +4825,16 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4256,6 +5362,26 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", @@ -4293,6 +5419,16 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", @@ -4621,6 +5757,13 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", @@ -4780,6 +5923,45 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmmirror.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -4854,6 +6036,57 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmmirror.com/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.5.0.tgz", + "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", @@ -4948,6 +6181,267 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", @@ -5023,6 +6517,55 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmmirror.com/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5033,6 +6576,13 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", @@ -5055,6 +6605,16 @@ "node": ">=8.6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", @@ -5107,9 +6667,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -5432,6 +6992,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/oidc-token-hash": { "version": "5.2.0", "resolved": "https://registry.npmmirror.com/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz", @@ -5568,6 +7139,19 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", @@ -5621,6 +7205,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", @@ -5658,13 +7249,13 @@ } }, "node_modules/playwright": { - "version": "1.59.1", - "resolved": "https://registry.npmmirror.com/playwright/-/playwright-1.59.1.tgz", - "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "version": "1.60.0", + "resolved": "https://registry.npmmirror.com/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.59.1" + "playwright-core": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -5677,9 +7268,9 @@ } }, "node_modules/playwright-core": { - "version": "1.59.1", - "resolved": "https://registry.npmmirror.com/playwright-core/-/playwright-core-1.59.1.tgz", - "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "version": "1.60.0", + "resolved": "https://registry.npmmirror.com/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -5714,9 +7305,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.15", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -5733,7 +7324,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -6159,6 +7750,20 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -6203,6 +7808,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "2.0.0-next.6", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-2.0.0-next.6.tgz", @@ -6296,6 +7911,40 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rolldown": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.2.tgz", + "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.132.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.2", + "@rolldown/binding-darwin-arm64": "1.0.2", + "@rolldown/binding-darwin-x64": "1.0.2", + "@rolldown/binding-freebsd-x64": "1.0.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", + "@rolldown/binding-linux-arm64-gnu": "1.0.2", + "@rolldown/binding-linux-arm64-musl": "1.0.2", + "@rolldown/binding-linux-ppc64-gnu": "1.0.2", + "@rolldown/binding-linux-s390x-gnu": "1.0.2", + "@rolldown/binding-linux-x64-gnu": "1.0.2", + "@rolldown/binding-linux-x64-musl": "1.0.2", + "@rolldown/binding-openharmony-arm64": "1.0.2", + "@rolldown/binding-wasm32-wasi": "1.0.2", + "@rolldown/binding-win32-arm64-msvc": "1.0.2", + "@rolldown/binding-win32-x64-msvc": "1.0.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6374,6 +8023,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", @@ -6544,6 +8206,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", @@ -6573,6 +8242,20 @@ "dev": true, "license": "MIT" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -6815,6 +8498,19 @@ "node": ">=4" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6898,6 +8594,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/swr/-/swr-2.4.1.tgz", + "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.5.0", "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.5.0.tgz", @@ -7009,6 +8725,23 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.16.tgz", @@ -7054,6 +8787,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.30", + "resolved": "https://registry.npmmirror.com/tldts/-/tldts-7.0.30.tgz", + "integrity": "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.30" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.30", + "resolved": "https://registry.npmmirror.com/tldts-core/-/tldts-core-7.0.30.tgz", + "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7066,6 +8829,32 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz", @@ -7241,6 +9030,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmmirror.com/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", @@ -7336,6 +9135,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7373,6 +9181,248 @@ "d3-timer": "^3.0.1" } }, + "node_modules/vite": { + "version": "8.0.14", + "resolved": "https://registry.npmmirror.com/vite/-/vite-8.0.14.tgz", + "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.2", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.7.tgz", + "integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.7", + "@vitest/mocker": "4.1.7", + "@vitest/pretty-format": "4.1.7", + "@vitest/runner": "4.1.7", + "@vitest/snapshot": "4.1.7", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.7", + "@vitest/browser-preview": "4.1.7", + "@vitest/browser-webdriverio": "4.1.7", + "@vitest/coverage-istanbul": "4.1.7", + "@vitest/coverage-v8": "4.1.7", + "@vitest/ui": "4.1.7", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", @@ -7478,6 +9528,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", @@ -7596,6 +9663,23 @@ "dev": true, "license": "ISC" }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", @@ -7614,6 +9698,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.13", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.13.tgz", + "integrity": "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/frontend/package.json b/frontend/package.json index 7084023..3287b31 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,9 @@ "lint": "next lint", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", - "test:e2e:headed": "playwright test --headed" + "test:e2e:headed": "playwright test --headed", + "test": "vitest", + "test:ci": "vitest run --coverage" }, "dependencies": { "@radix-ui/react-dialog": "^1.1.15", @@ -27,18 +29,26 @@ "react": "^18", "react-dom": "^18", "recharts": "^2.15.4", + "swr": "^2.4.1", "tailwind-merge": "^3.5.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.13" }, "devDependencies": { - "@playwright/test": "^1.59.1", + "@playwright/test": "^1.60.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@vitejs/plugin-react": "^6.0.2", + "@vitest/coverage-v8": "^4.1.7", "eslint": "^8", "eslint-config-next": "14.2.35", + "jsdom": "^29.1.1", "postcss": "^8", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.1.7" } } diff --git a/frontend/playwright-report/data/02c38299aac52370c08620b8c68905e55ba39c4b.png b/frontend/playwright-report/data/02c38299aac52370c08620b8c68905e55ba39c4b.png deleted file mode 100644 index 6d4dec9..0000000 Binary files a/frontend/playwright-report/data/02c38299aac52370c08620b8c68905e55ba39c4b.png and /dev/null differ diff --git a/frontend/playwright-report/data/050b25ad409e051f9fc12fa8d03dd42cc4eb465a.zip b/frontend/playwright-report/data/050b25ad409e051f9fc12fa8d03dd42cc4eb465a.zip deleted file mode 100644 index 9daed0a..0000000 Binary files a/frontend/playwright-report/data/050b25ad409e051f9fc12fa8d03dd42cc4eb465a.zip and /dev/null differ diff --git a/frontend/playwright-report/data/0aa98d58fee49c33b668c9262312fba8fbbc8b8b.md b/frontend/playwright-report/data/0aa98d58fee49c33b668c9262312fba8fbbc8b8b.md deleted file mode 100644 index e5b6f65..0000000 --- a/frontend/playwright-report/data/0aa98d58fee49c33b668c9262312fba8fbbc8b8b.md +++ /dev/null @@ -1,163 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: dashboard-health.spec.ts >> 健康状态Dashboard - 响应式设计测试 >> 移动端视口下概览卡片堆叠显示 -- Location: e2e/tests/dashboard-health.spec.ts:239:7 - -# Error details - -``` -Error: expect(locator).toBeVisible() failed - -Locator: locator('text=综合评分').first() -Expected: visible -Timeout: 10000ms -Error: element(s) not found - -Call log: - - Expect "toBeVisible" with timeout 10000ms - - waiting for locator('text=综合评分').first() - -``` - -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - alert [ref=e2] - - generic [ref=e3]: - - complementary [ref=e4]: - - generic [ref=e6]: GEO Platform - - navigation [ref=e7]: - - link "数据总览" [ref=e8] [cursor=pointer]: - - /url: /dashboard - - img [ref=e9] - - text: 数据总览 - - link "品牌管理" [ref=e14] [cursor=pointer]: - - /url: /brands - - img [ref=e15] - - text: 品牌管理 - - link "竞品对比" [ref=e17] [cursor=pointer]: - - /url: /compare - - img [ref=e18] - - text: 竞品对比 - - link "查询管理" [ref=e23] [cursor=pointer]: - - /url: /dashboard/queries - - img [ref=e24] - - text: 查询管理 - - link "引用记录" [ref=e27] [cursor=pointer]: - - /url: /dashboard/citations - - img [ref=e28] - - text: 引用记录 - - link "报告导出" [ref=e31] [cursor=pointer]: - - /url: /dashboard/reports - - img [ref=e32] - - text: 报告导出 - - link "设置" [ref=e36] [cursor=pointer]: - - /url: /dashboard/settings - - img [ref=e37] - - text: 设置 - - link "管理后台" [ref=e40] [cursor=pointer]: - - /url: /dashboard/admin - - img [ref=e41] - - text: 管理后台 - - generic [ref=e43]: - - banner [ref=e44]: - - heading "GEO Platform" [level=1] [ref=e45] - - generic [ref=e46]: - - generic [ref=e47]: - - img [ref=e48] - - generic [ref=e51]: 管理员 - - button "退出登录" [ref=e52] [cursor=pointer]: - - img [ref=e53] - - text: 退出登录 - - main [ref=e56]: - - generic [ref=e57]: - - paragraph [ref=e58]: Failed to fetch - - button "重新加载" [ref=e59] [cursor=pointer] -``` - -# Test source - -```ts - 1 | import { Page, Locator, expect } from "@playwright/test"; - 2 | - 3 | export class DashboardPage { - 4 | readonly page: Page; - 5 | readonly pageTitle: Locator; - 6 | readonly healthScoreCard: Locator; - 7 | readonly competitorStatusCard: Locator; - 8 | readonly trendCard: Locator; - 9 | readonly monitorPlatformCard: Locator; - 10 | readonly platformScoreList: Locator; - 11 | readonly actionSuggestions: Locator; - 12 | - 13 | constructor(page: Page) { - 14 | this.page = page; - 15 | // 品牌健康中心标题 - 16 | this.pageTitle = page.getByRole("heading", { name: "品牌健康中心" }); - 17 | // 概览卡片 - 18 | this.healthScoreCard = page.locator("text=综合评分").first(); - 19 | this.competitorStatusCard = page.locator("text=竞品地位").first(); - 20 | this.trendCard = page.locator("text=趋势").first(); - 21 | this.monitorPlatformCard = page.locator("text=监控平台").first(); - 22 | // 平台评分列表 - 23 | this.platformScoreList = page.locator("text=平台评分详情"); - 24 | // 行动建议 - 25 | this.actionSuggestions = page.locator("text=为您推荐的下一步行动"); - 26 | } - 27 | - 28 | async goto() { - 29 | await this.page.goto("/dashboard"); - 30 | } - 31 | - 32 | async expectToBeVisible() { - 33 | await expect(this.pageTitle).toBeVisible(); - 34 | } - 35 | - 36 | // 等待健康状态卡片加载 - 37 | async waitForHealthCards() { -> 38 | await expect(this.healthScoreCard).toBeVisible({ timeout: 10000 }); - | ^ Error: expect(locator).toBeVisible() failed - 39 | } - 40 | - 41 | // 获取综合评分值 - 42 | async getOverallScore(): Promise { - 43 | const scoreElement = this.page.locator(".text-5xl.font-bold").first(); - 44 | if (await scoreElement.isVisible()) { - 45 | return scoreElement.textContent(); - 46 | } - 47 | return null; - 48 | } - 49 | - 50 | // 获取健康等级标签 - 51 | async getHealthLevel(): Promise { - 52 | return this.page.locator(".rounded-full.px-3.py-1.text-sm.font-medium").first(); - 53 | } - 54 | - 55 | // 获取平台评分项数量 - 56 | async getPlatformScoreCount(): Promise { - 57 | const items = this.page.locator("text=/文心一言|Kimi|通义千问|豆包|讯飞星火|天工AI|智谱清言/"); - 58 | return items.count(); - 59 | } - 60 | - 61 | // 获取行动建议数量 - 62 | async getActionSuggestionCount(): Promise { - 63 | const suggestions = this.page.locator(".rounded-lg.border p-4"); - 64 | return suggestions.count(); - 65 | } - 66 | - 67 | // 检查危险平台是否被高亮 - 68 | async isDangerPlatformHighlighted(): Promise { - 69 | const dangerCard = this.page.locator(".border-red-200.bg-red-50\\/50"); - 70 | const count = await dangerCard.count(); - 71 | return count > 0; - 72 | } - 73 | } - 74 | -``` \ No newline at end of file diff --git a/frontend/playwright-report/data/0af630aa468fe7ee067da8e5a5eab9ce0475d05c.zip b/frontend/playwright-report/data/0af630aa468fe7ee067da8e5a5eab9ce0475d05c.zip deleted file mode 100644 index 582eda8..0000000 Binary files a/frontend/playwright-report/data/0af630aa468fe7ee067da8e5a5eab9ce0475d05c.zip and /dev/null differ diff --git a/frontend/playwright-report/data/a770454080c2b67f718462fa287b42ea71165a06.png b/frontend/playwright-report/data/a770454080c2b67f718462fa287b42ea71165a06.png deleted file mode 100644 index b678fea..0000000 Binary files a/frontend/playwright-report/data/a770454080c2b67f718462fa287b42ea71165a06.png and /dev/null differ diff --git a/frontend/playwright-report/data/e08296d1ab8d4f03cce50a6e50dfd7a19a360922.md b/frontend/playwright-report/data/e08296d1ab8d4f03cce50a6e50dfd7a19a360922.md deleted file mode 100644 index 2cb413e..0000000 --- a/frontend/playwright-report/data/e08296d1ab8d4f03cce50a6e50dfd7a19a360922.md +++ /dev/null @@ -1,326 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: onboarding.spec.ts >> 新用户引导向导 - 完整流程测试 >> Step 1: 应该显示品牌名称输入页面 -- Location: e2e/tests/onboarding.spec.ts:144:7 - -# Error details - -``` -Error: expect(locator).toHaveCount(expected) failed - -Locator: locator('.flex.items-center.justify-between > div') -Expected: 5 -Received: 6 -Timeout: 5000ms - -Call log: - - Expect "toHaveCount" with timeout 5000ms - - waiting for locator('.flex.items-center.justify-between > div') - 9 × locator resolved to 6 elements - - unexpected value "6" - -``` - -# Page snapshot - -```yaml -- generic [ref=e1]: - - generic [ref=e2]: - - complementary [ref=e3]: - - generic [ref=e5]: GEO Platform - - navigation [ref=e6]: - - link "数据总览" [ref=e7] [cursor=pointer]: - - /url: /dashboard - - img [ref=e8] - - text: 数据总览 - - link "品牌管理" [ref=e13] [cursor=pointer]: - - /url: /brands - - img [ref=e14] - - text: 品牌管理 - - link "竞品对比" [ref=e16] [cursor=pointer]: - - /url: /compare - - img [ref=e17] - - text: 竞品对比 - - link "查询管理" [ref=e22] [cursor=pointer]: - - /url: /dashboard/queries - - img [ref=e23] - - text: 查询管理 - - link "引用记录" [ref=e26] [cursor=pointer]: - - /url: /dashboard/citations - - img [ref=e27] - - text: 引用记录 - - link "报告导出" [ref=e30] [cursor=pointer]: - - /url: /dashboard/reports - - img [ref=e31] - - text: 报告导出 - - link "设置" [ref=e35] [cursor=pointer]: - - /url: /dashboard/settings - - img [ref=e36] - - text: 设置 - - link "管理后台" [ref=e39] [cursor=pointer]: - - /url: /dashboard/admin - - img [ref=e40] - - text: 管理后台 - - generic [ref=e42]: - - banner [ref=e43]: - - heading "GEO Platform" [level=1] [ref=e44] - - generic [ref=e45]: - - generic [ref=e46]: - - img [ref=e47] - - generic [ref=e50]: 管理员 - - button "退出登录" [ref=e51] [cursor=pointer]: - - img [ref=e52] - - text: 退出登录 - - main [ref=e55]: - - generic [ref=e57]: - - generic [ref=e58]: - - heading "GEO 平台" [level=1] [ref=e59] - - paragraph [ref=e60]: 新用户引导 - - generic [ref=e63]: - - generic [ref=e65]: - - generic [ref=e67]: "1" - - generic [ref=e68]: 输入品牌名称 - - generic [ref=e71]: - - generic [ref=e73]: "2" - - generic [ref=e74]: 确认竞品 - - generic [ref=e77]: - - generic [ref=e79]: "3" - - generic [ref=e80]: 选择平台 - - generic [ref=e83]: - - generic [ref=e85]: "4" - - generic [ref=e86]: 健康报告 - - generic [ref=e89]: - - generic [ref=e91]: "5" - - generic [ref=e92]: 行动建议 - - generic [ref=e94]: - - generic [ref=e95]: - - img [ref=e97] - - heading "输入您的品牌名称" [level=2] [ref=e100] - - paragraph [ref=e101]: 输入您要在AI搜索中监控的品牌名称,我们将为您分析其曝光度 - - generic [ref=e104]: - - generic [ref=e105]: - - generic [ref=e106]: 品牌名称 * - - textbox "品牌名称 *" [active] [ref=e107]: - - /placeholder: 例如:华为、小米、苹果 - - paragraph [ref=e108]: 品牌名称创建后可以修改,最多50个字符 - - generic [ref=e109]: - - button "开始分析" [disabled]: - - text: 开始分析 - - img - - button "跳过,直接进入Dashboard" [ref=e110] [cursor=pointer] - - generic [ref=e113]: 输入品牌名称后,系统将自动开始监控 - - alert [ref=e114] -``` - -# Test source - -```ts - 61 | this.addCompetitorButton = this.page - 62 | .locator('button:has-text("添加")') - 63 | .first(); - 64 | this.nextButton = this.page.getByRole("button", { name: /继续/ }); - 65 | this.backButton = this.page.getByRole("button", { name: /上一步/ }); - 66 | this.skipStepButton = this.page.getByRole("button", { name: /跳过此步骤/ }); - 67 | - 68 | // Step 3 - 69 | this.platformCheckboxes = this.page.locator(".grid.gap-3 button"); - 70 | this.selectAllButton = this.page.getByRole("button", { name: "全选" }); - 71 | this.queryFrequencyOptions = this.page.locator(".grid.gap-3 button"); - 72 | - 73 | // Step 4 - 74 | this.healthScore = this.page.locator("text-7xl.font-bold"); - 75 | this.healthLevelBadge = this.page.locator("text-base.px-4.py-1"); - 76 | this.viewActionsButton = this.page.getByRole("button", { - 77 | name: /查看行动建议/, - 78 | }); - 79 | - 80 | // Step 5 - 81 | this.completeButton = this.page.getByRole("button", { name: /完成设置/ }); - 82 | - 83 | // 进度指示器 - 84 | this.progressSteps = this.page.locator( - 85 | ".flex.items-center.justify-between > div", - 86 | ); - 87 | } - 88 | - 89 | async goto() { - 90 | await this.page.goto("/onboarding"); - 91 | } - 92 | - 93 | async loginAndGoToOnboarding() { - 94 | const loginPage = new LoginPage(this.page); - 95 | await loginPage.goto(); - 96 | await loginPage.login(TEST_USER.email, TEST_USER.password); - 97 | - 98 | // 等待登录完成并跳转到Dashboard - 99 | // 使用更长的超时时间和更多的等待条件 - 100 | try { - 101 | await this.page.waitForURL(/\/dashboard/, { timeout: 20000 }); - 102 | } catch (e) { - 103 | // 如果超时,检查当前URL - 104 | console.log("Current URL after login timeout:", this.page.url()); - 105 | throw e; - 106 | } - 107 | await this.page.goto("/onboarding"); - 108 | } - 109 | - 110 | async fillBrandName(name: string) { - 111 | await this.brandNameInput.fill(name); - 112 | } - 113 | - 114 | async clickStartAnalysis() { - 115 | await this.startAnalysisButton.click(); - 116 | } - 117 | - 118 | async selectCompetitor(name: string) { - 119 | const competitorCard = this.page - 120 | .locator(".border.rounded-lg") - 121 | .filter({ hasText: name }); - 122 | await competitorCard.click(); - 123 | } - 124 | - 125 | async selectPlatform(platformName: string) { - 126 | const platformCard = this.page - 127 | .locator(".grid.gap-3 button") - 128 | .filter({ hasText: platformName }); - 129 | await platformCard.click(); - 130 | } - 131 | - 132 | async selectQueryFrequency(frequency: string) { - 133 | await this.queryFrequencyOptions.filter({ hasText: frequency }).click(); - 134 | } - 135 | } - 136 | - 137 | describe("新用户引导向导 - 完整流程测试", () => { - 138 | test.beforeEach(async ({ page }) => { - 139 | // 先登录 - 140 | const onboardingPage = new OnboardingPage(page); - 141 | await onboardingPage.loginAndGoToOnboarding(); - 142 | }); - 143 | - 144 | test("Step 1: 应该显示品牌名称输入页面", async ({ page }) => { - 145 | const onboardingPage = new OnboardingPage(page); - 146 | await onboardingPage.goto(); - 147 | - 148 | // 验证标题 - 149 | await expect( - 150 | page.getByRole("heading", { name: /输入您的品牌名称/ }), - 151 | ).toBeVisible(); - 152 | - 153 | // 验证输入框存在 - 154 | await expect(onboardingPage.brandNameInput).toBeVisible(); - 155 | - 156 | // 验证按钮存在 - 157 | await expect(onboardingPage.startAnalysisButton).toBeVisible(); - 158 | await expect(onboardingPage.skipToDashboardButton).toBeVisible(); - 159 | - 160 | // 验证进度指示器 -> 161 | await expect(onboardingPage.progressSteps).toHaveCount(5); - | ^ Error: expect(locator).toHaveCount(expected) failed - 162 | }); - 163 | - 164 | test("Step 1: 品牌名称验证 - 太短应显示错误", async ({ page }) => { - 165 | const onboardingPage = new OnboardingPage(page); - 166 | await onboardingPage.goto(); - 167 | - 168 | // 输入太短的名称 - 169 | await onboardingPage.fillBrandName("a"); - 170 | await onboardingPage.startAnalysisButton.click(); - 171 | - 172 | // 应该显示错误提示 - 173 | await expect(page.getByText(/至少需要2个字符/)).toBeVisible(); - 174 | }); - 175 | - 176 | test("Step 1: 正确输入品牌名称应进入下一步", async ({ page }) => { - 177 | const onboardingPage = new OnboardingPage(page); - 178 | await onboardingPage.goto(); - 179 | - 180 | // 输入有效的品牌名称 - 181 | await onboardingPage.fillBrandName("华为"); - 182 | await onboardingPage.startAnalysisButton.click(); - 183 | - 184 | // 应该进入Step 2 - 185 | await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ - 186 | timeout: 5000, - 187 | }); - 188 | }); - 189 | - 190 | test("Step 2: 可以选择竞品并继续", async ({ page }) => { - 191 | const onboardingPage = new OnboardingPage(page); - 192 | await onboardingPage.goto(); - 193 | - 194 | // Step 1 - 195 | await onboardingPage.fillBrandName("华为"); - 196 | await onboardingPage.startAnalysisButton.click(); - 197 | - 198 | // Step 2 - 等待加载 - 199 | await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ - 200 | timeout: 5000, - 201 | }); - 202 | - 203 | // 等待推荐竞品加载 - 204 | await page.waitForTimeout(2000); - 205 | - 206 | // 选择一个竞品(如果存在的话) - 207 | const firstCompetitor = page - 208 | .locator(".border.rounded-lg") - 209 | .filter({ has: page.locator(".flex.h-5.w-5") }) - 210 | .first(); - 211 | if (await firstCompetitor.isVisible()) { - 212 | await firstCompetitor.click(); - 213 | } - 214 | - 215 | // 点击继续 - 216 | await onboardingPage.nextButton.click(); - 217 | - 218 | // 应该进入Step 3 - 219 | await expect( - 220 | page.getByRole("heading", { name: /选择监控平台/ }), - 221 | ).toBeVisible({ timeout: 5000 }); - 222 | }); - 223 | - 224 | test("Step 2: 跳过应进入下一步", async ({ page }) => { - 225 | const onboardingPage = new OnboardingPage(page); - 226 | await onboardingPage.goto(); - 227 | - 228 | // Step 1 - 229 | await onboardingPage.fillBrandName("华为"); - 230 | await onboardingPage.startAnalysisButton.click(); - 231 | - 232 | // Step 2 - 点击跳过 - 233 | await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ - 234 | timeout: 5000, - 235 | }); - 236 | await onboardingPage.skipStepButton.click(); - 237 | - 238 | // 应该进入Step 3 - 239 | await expect( - 240 | page.getByRole("heading", { name: /选择监控平台/ }), - 241 | ).toBeVisible({ timeout: 5000 }); - 242 | }); - 243 | - 244 | test("Step 3: 平台默认全选", async ({ page }) => { - 245 | const onboardingPage = new OnboardingPage(page); - 246 | await onboardingPage.goto(); - 247 | - 248 | // Step 1 -> Step 2 -> Step 3 - 249 | await onboardingPage.fillBrandName("华为"); - 250 | await onboardingPage.startAnalysisButton.click(); - 251 | await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ - 252 | timeout: 5000, - 253 | }); - 254 | await onboardingPage.skipStepButton.click(); - 255 | await expect( - 256 | page.getByRole("heading", { name: /选择监控平台/ }), - 257 | ).toBeVisible({ timeout: 5000 }); - 258 | - 259 | // 验证平台数量提示 - 260 | await expect(page.getByText(/\d+\/\d+ 个平台/)).toBeVisible(); - 261 | }); -``` \ No newline at end of file diff --git a/frontend/playwright-report/data/e9d1096a19c3b50b45a2152b014a556e77478e7a.zip b/frontend/playwright-report/data/e9d1096a19c3b50b45a2152b014a556e77478e7a.zip deleted file mode 100644 index 7460b7e..0000000 Binary files a/frontend/playwright-report/data/e9d1096a19c3b50b45a2152b014a556e77478e7a.zip and /dev/null differ diff --git a/frontend/playwright-report/data/f1cb5d781ba020854958d9fb3ba23df08bbfc43b.png b/frontend/playwright-report/data/f1cb5d781ba020854958d9fb3ba23df08bbfc43b.png deleted file mode 100644 index fbabed9..0000000 Binary files a/frontend/playwright-report/data/f1cb5d781ba020854958d9fb3ba23df08bbfc43b.png and /dev/null differ diff --git a/frontend/playwright-report/data/fdab206a1be07b21d163a356f73e82c7e838e003.md b/frontend/playwright-report/data/fdab206a1be07b21d163a356f73e82c7e838e003.md deleted file mode 100644 index c8fc044..0000000 --- a/frontend/playwright-report/data/fdab206a1be07b21d163a356f73e82c7e838e003.md +++ /dev/null @@ -1,163 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: dashboard-health.spec.ts >> 健康状态Dashboard - 颜色传达状态测试 >> 趋势箭头颜色正确(绿涨红跌) -- Location: e2e/tests/dashboard-health.spec.ts:219:7 - -# Error details - -``` -Error: expect(locator).toBeVisible() failed - -Locator: locator('text=综合评分').first() -Expected: visible -Timeout: 10000ms -Error: element(s) not found - -Call log: - - Expect "toBeVisible" with timeout 10000ms - - waiting for locator('text=综合评分').first() - -``` - -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - alert [ref=e2] - - generic [ref=e3]: - - complementary [ref=e4]: - - generic [ref=e6]: GEO Platform - - navigation [ref=e7]: - - link "数据总览" [ref=e8] [cursor=pointer]: - - /url: /dashboard - - img [ref=e9] - - text: 数据总览 - - link "品牌管理" [ref=e14] [cursor=pointer]: - - /url: /brands - - img [ref=e15] - - text: 品牌管理 - - link "竞品对比" [ref=e17] [cursor=pointer]: - - /url: /compare - - img [ref=e18] - - text: 竞品对比 - - link "查询管理" [ref=e23] [cursor=pointer]: - - /url: /dashboard/queries - - img [ref=e24] - - text: 查询管理 - - link "引用记录" [ref=e27] [cursor=pointer]: - - /url: /dashboard/citations - - img [ref=e28] - - text: 引用记录 - - link "报告导出" [ref=e31] [cursor=pointer]: - - /url: /dashboard/reports - - img [ref=e32] - - text: 报告导出 - - link "设置" [ref=e36] [cursor=pointer]: - - /url: /dashboard/settings - - img [ref=e37] - - text: 设置 - - link "管理后台" [ref=e40] [cursor=pointer]: - - /url: /dashboard/admin - - img [ref=e41] - - text: 管理后台 - - generic [ref=e43]: - - banner [ref=e44]: - - heading "GEO Platform" [level=1] [ref=e45] - - generic [ref=e46]: - - generic [ref=e47]: - - img [ref=e48] - - generic [ref=e51]: 管理员 - - button "退出登录" [ref=e52] [cursor=pointer]: - - img [ref=e53] - - text: 退出登录 - - main [ref=e56]: - - generic [ref=e57]: - - paragraph [ref=e58]: Failed to fetch - - button "重新加载" [ref=e59] [cursor=pointer] -``` - -# Test source - -```ts - 1 | import { Page, Locator, expect } from "@playwright/test"; - 2 | - 3 | export class DashboardPage { - 4 | readonly page: Page; - 5 | readonly pageTitle: Locator; - 6 | readonly healthScoreCard: Locator; - 7 | readonly competitorStatusCard: Locator; - 8 | readonly trendCard: Locator; - 9 | readonly monitorPlatformCard: Locator; - 10 | readonly platformScoreList: Locator; - 11 | readonly actionSuggestions: Locator; - 12 | - 13 | constructor(page: Page) { - 14 | this.page = page; - 15 | // 品牌健康中心标题 - 16 | this.pageTitle = page.getByRole("heading", { name: "品牌健康中心" }); - 17 | // 概览卡片 - 18 | this.healthScoreCard = page.locator("text=综合评分").first(); - 19 | this.competitorStatusCard = page.locator("text=竞品地位").first(); - 20 | this.trendCard = page.locator("text=趋势").first(); - 21 | this.monitorPlatformCard = page.locator("text=监控平台").first(); - 22 | // 平台评分列表 - 23 | this.platformScoreList = page.locator("text=平台评分详情"); - 24 | // 行动建议 - 25 | this.actionSuggestions = page.locator("text=为您推荐的下一步行动"); - 26 | } - 27 | - 28 | async goto() { - 29 | await this.page.goto("/dashboard"); - 30 | } - 31 | - 32 | async expectToBeVisible() { - 33 | await expect(this.pageTitle).toBeVisible(); - 34 | } - 35 | - 36 | // 等待健康状态卡片加载 - 37 | async waitForHealthCards() { -> 38 | await expect(this.healthScoreCard).toBeVisible({ timeout: 10000 }); - | ^ Error: expect(locator).toBeVisible() failed - 39 | } - 40 | - 41 | // 获取综合评分值 - 42 | async getOverallScore(): Promise { - 43 | const scoreElement = this.page.locator(".text-5xl.font-bold").first(); - 44 | if (await scoreElement.isVisible()) { - 45 | return scoreElement.textContent(); - 46 | } - 47 | return null; - 48 | } - 49 | - 50 | // 获取健康等级标签 - 51 | async getHealthLevel(): Promise { - 52 | return this.page.locator(".rounded-full.px-3.py-1.text-sm.font-medium").first(); - 53 | } - 54 | - 55 | // 获取平台评分项数量 - 56 | async getPlatformScoreCount(): Promise { - 57 | const items = this.page.locator("text=/文心一言|Kimi|通义千问|豆包|讯飞星火|天工AI|智谱清言/"); - 58 | return items.count(); - 59 | } - 60 | - 61 | // 获取行动建议数量 - 62 | async getActionSuggestionCount(): Promise { - 63 | const suggestions = this.page.locator(".rounded-lg.border p-4"); - 64 | return suggestions.count(); - 65 | } - 66 | - 67 | // 检查危险平台是否被高亮 - 68 | async isDangerPlatformHighlighted(): Promise { - 69 | const dangerCard = this.page.locator(".border-red-200.bg-red-50\\/50"); - 70 | const count = await dangerCard.count(); - 71 | return count > 0; - 72 | } - 73 | } - 74 | -``` \ No newline at end of file diff --git a/frontend/playwright-report/index.html b/frontend/playwright-report/index.html index 46a1d23..24a21ba 100644 --- a/frontend/playwright-report/index.html +++ b/frontend/playwright-report/index.html @@ -7,7 +7,7 @@ Playwright Test Report - -
- \ No newline at end of file + \ No newline at end of file diff --git a/frontend/playwright-report/trace/assets/codeMirrorModule-DS0FLvoc.js b/frontend/playwright-report/trace/assets/codeMirrorModule-DS0FLvoc.js deleted file mode 100644 index 3f0e8bf..0000000 --- a/frontend/playwright-report/trace/assets/codeMirrorModule-DS0FLvoc.js +++ /dev/null @@ -1,32 +0,0 @@ -import{v as Ju}from"./defaultSettingsView-GTWI-W_B.js";var vi={exports:{}},Zu=vi.exports,pa;function mt(){return pa||(pa=1,(function(ct,xt){(function(b,pe){ct.exports=pe()})(Zu,(function(){var b=navigator.userAgent,pe=navigator.platform,_=/gecko\/\d/i.test(b),te=/MSIE \d/.test(b),oe=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(b),Q=/Edge\/(\d+)/.exec(b),k=te||oe||Q,I=k&&(te?document.documentMode||6:+(Q||oe)[1]),Y=!Q&&/WebKit\//.test(b),ne=Y&&/Qt\/\d+\.\d+/.test(b),S=!Q&&/Chrome\/(\d+)/.exec(b),R=S&&+S[1],A=/Opera\//.test(b),$=/Apple Computer/.test(navigator.vendor),ue=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(b),O=/PhantomJS/.test(b),w=$&&(/Mobile\/\w+/.test(b)||navigator.maxTouchPoints>2),M=/Android/.test(b),N=w||M||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(b),z=w||/Mac/.test(pe),X=/\bCrOS\b/.test(b),q=/win/i.test(pe),p=A&&b.match(/Version\/(\d*\.\d*)/);p&&(p=Number(p[1])),p&&p>=15&&(A=!1,Y=!0);var W=z&&(ne||A&&(p==null||p<12.11)),J=_||k&&I>=9;function P(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var V=function(e,t){var n=e.className,r=P(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}};function F(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function G(e,t){return F(e).appendChild(t)}function c(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),typeof t=="string")i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return l+(t-o);l+=a-o,l+=n-l%n,o=a+1}}var Ce=function(){this.id=null,this.f=null,this.time=0,this.handler=xe(this.onTimeout,this)};Ce.prototype.onTimeout=function(e){e.id=0,e.time<=+new Date?e.f():setTimeout(e.handler,e.time-+new Date)},Ce.prototype.set=function(e,t){this.f=t;var n=+new Date+e;(!this.id||n=t)return r+Math.min(l,t-i);if(i+=o-r,i+=n-i%n,r=o+1,i>=t)return r}}var Ue=[""];function et(e){for(;Ue.length<=e;)Ue.push(we(Ue)+" ");return Ue[e]}function we(e){return e[e.length-1]}function Ie(e,t){for(var n=[],r=0;r"€"&&(e.toUpperCase()!=e.toLowerCase()||ze.test(e))}function De(e,t){return t?t.source.indexOf("\\w")>-1&&me(e)?!0:t.test(e):me(e)}function be(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var Be=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function Ne(e){return e.charCodeAt(0)>=768&&Be.test(e)}function Mt(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function or(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;ot||t==n&&l.to==t)&&(r(Math.max(l.from,t),Math.min(l.to,n),l.level==1?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}var br=null;function lr(e,t,n){var r;br=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&n=="before"?r=i:br=i),o.from==t&&(o.from!=o.to&&n!="before"?r=i:br=i)}return r??br}var mi=(function(){var e="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",t="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function n(u){return u<=247?e.charAt(u):1424<=u&&u<=1524?"R":1536<=u&&u<=1785?t.charAt(u-1536):1774<=u&&u<=2220?"r":8192<=u&&u<=8203?"w":u==8204?"b":"L"}var r=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,i=/[stwN]/,o=/[LRr]/,l=/[Lb1n]/,a=/[1n]/;function s(u,h,x){this.level=u,this.from=h,this.to=x}return function(u,h){var x=h=="ltr"?"L":"R";if(u.length==0||h=="ltr"&&!r.test(u))return!1;for(var D=u.length,L=[],H=0;H-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function Ye(e,t){var n=Zt(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function Bt(e){e.prototype.on=function(t,n){Se(this,t,n)},e.prototype.off=function(t,n){ht(this,t,n)}}function pt(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Er(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function kt(e){return e.defaultPrevented!=null?e.defaultPrevented:e.returnValue==!1}function ar(e){pt(e),Er(e)}function ln(e){return e.target||e.srcElement}function Rt(e){var t=e.which;return t==null&&(e.button&1?t=1:e.button&2?t=3:e.button&4&&(t=2)),z&&e.ctrlKey&&t==1&&(t=3),t}var xi=(function(){if(k&&I<9)return!1;var e=c("div");return"draggable"in e||"dragDrop"in e})(),Or;function Rn(e){if(Or==null){var t=c("span","​");G(e,c("span",[t,document.createTextNode("x")])),e.firstChild.offsetHeight!=0&&(Or=t.offsetWidth<=1&&t.offsetHeight>2&&!(k&&I<8))}var n=Or?c("span","​"):c("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}var an;function sr(e){if(an!=null)return an;var t=G(e,document.createTextNode("AخA")),n=C(t,0,1).getBoundingClientRect(),r=C(t,1,2).getBoundingClientRect();return F(e),!n||n.left==n.right?!1:an=r.right-n.right<3}var zt=` - -b`.split(/\n/).length!=3?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf(` -`,t);i==-1&&(i=e.length);var o=e.slice(t,e.charAt(i-1)=="\r"?i-1:i),l=o.indexOf("\r");l!=-1?(n.push(o.slice(0,l)),t+=l+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},ur=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch{return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch{}return!t||t.parentElement()!=e?!1:t.compareEndPoints("StartToEnd",t)!=0},Wn=(function(){var e=c("div");return"oncopy"in e?!0:(e.setAttribute("oncopy","return;"),typeof e.oncopy=="function")})(),Wt=null;function yi(e){if(Wt!=null)return Wt;var t=G(e,c("span","x")),n=t.getBoundingClientRect(),r=C(t,0,1).getBoundingClientRect();return Wt=Math.abs(n.left-r.left)>1}var Pr={},Ht={};function _t(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Pr[e]=t}function kr(e,t){Ht[e]=t}function Ir(e){if(typeof e=="string"&&Ht.hasOwnProperty(e))e=Ht[e];else if(e&&typeof e.name=="string"&&Ht.hasOwnProperty(e.name)){var t=Ht[e.name];typeof t=="string"&&(t={name:t}),e=K(t,e),e.name=t.name}else{if(typeof e=="string"&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return Ir("application/xml");if(typeof e=="string"&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return Ir("application/json")}return typeof e=="string"?{name:e}:e||{name:"null"}}function zr(e,t){t=Ir(t);var n=Pr[t.name];if(!n)return zr(e,"text/plain");var r=n(e,t);if(fr.hasOwnProperty(t.name)){var i=fr[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var l in t.modeProps)r[l]=t.modeProps[l];return r}var fr={};function Br(e,t){var n=fr.hasOwnProperty(e)?fr[e]:fr[e]={};Me(t,n)}function Gt(e,t){if(t===!0)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function sn(e,t){for(var n;e.innerMode&&(n=e.innerMode(t),!(!n||n.mode==e));)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Rr(e,t,n){return e.startState?e.startState(t,n):!0}var Je=function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n};Je.prototype.eol=function(){return this.pos>=this.string.length},Je.prototype.sol=function(){return this.pos==this.lineStart},Je.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Je.prototype.next=function(){if(this.post},Je.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Je.prototype.skipToEnd=function(){this.pos=this.string.length},Je.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Je.prototype.backUp=function(e){this.pos-=e},Je.prototype.column=function(){return this.lastColumnPos0?null:(o&&t!==!1&&(this.pos+=o[0].length),o)}},Je.prototype.current=function(){return this.string.slice(this.start,this.pos)},Je.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Je.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Je.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};function ye(e,t){if(t-=e.first,t<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?B(n,ye(e,n).text.length):Za(t,ye(e,t.line).text.length)}function Za(e,t){var n=e.ch;return n==null||n>t?B(e.line,t):n<0?B(e.line,0):e}function vo(e,t){for(var n=[],r=0;rthis.maxLookAhead&&(this.maxLookAhead=e),t},Xt.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},Xt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},Xt.fromSaved=function(e,t,n){return t instanceof Hn?new Xt(e,Gt(e.mode,t.state),n,t.lookAhead):new Xt(e,Gt(e.mode,t),n)},Xt.prototype.save=function(e){var t=e!==!1?Gt(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new Hn(t,this.maxLookAhead):t};function mo(e,t,n,r){var i=[e.state.modeGen],o={};So(e,t.text,e.doc.mode,n,function(u,h){return i.push(u,h)},o,r);for(var l=n.state,a=function(u){n.baseTokens=i;var h=e.state.overlays[u],x=1,D=0;n.state=!0,So(e,t.text,h.mode,n,function(L,H){for(var Z=x;DL&&i.splice(x,1,L,i[x+1],ie),x+=2,D=Math.min(L,ie)}if(H)if(h.opaque)i.splice(Z,x-Z,L,"overlay "+H),x=Z+2;else for(;Ze.options.maxHighlightLength&&Gt(e.doc.mode,r.state),o=mo(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function fn(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new Xt(r,!0,t);var o=$a(e,t,n),l=o>r.first&&ye(r,o-1).stateAfter,a=l?Xt.fromSaved(r,l,o):new Xt(r,Rr(r.mode),o);return r.iter(o,t,function(s){bi(e,s.text,a);var u=a.line;s.stateAfter=u==t-1||u%5==0||u>=i.viewFrom&&ut.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}var bo=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n};function ko(e,t,n,r){var i=e.doc,o=i.mode,l;t=Ae(i,t);var a=ye(i,t.line),s=fn(e,t.line,n),u=new Je(a.text,e.options.tabSize,s),h;for(r&&(h=[]);(r||u.pose.options.maxHighlightLength?(a=!1,l&&bi(e,t,r,h.pos),h.pos=t.length,x=null):x=wo(ki(n,h,r.state,D),o),D){var L=D[0].name;L&&(x="m-"+(x?L+" "+x:L))}if(!a||u!=x){for(;sl;--a){if(a<=o.first)return o.first;var s=ye(o,a-1),u=s.stateAfter;if(u&&(!n||a+(u instanceof Hn?u.lookAhead:0)<=o.modeFrontier))return a;var h=Fe(s.text,null,e.options.tabSize);(i==null||r>h)&&(i=a-1,r=h)}return i}function Va(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=ye(e,r).stateAfter;if(i&&(!(i instanceof Hn)||r+i.lookAhead=t:o.to>t);(r||(r=[])).push(new _n(l,o.from,s?null:o.to))}}return r}function os(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t);if(a||o.from==t&&l.type=="bookmark"&&(!n||o.marker.insertLeft)){var s=o.from==null||(l.inclusiveLeft?o.from<=t:o.from0&&a)for(var ge=0;ge0)){var h=[s,1],x=ce(u.from,a.from),D=ce(u.to,a.to);(x<0||!l.inclusiveLeft&&!x)&&h.push({from:u.from,to:a.from}),(D>0||!l.inclusiveRight&&!D)&&h.push({from:a.to,to:u.to}),i.splice.apply(i,h),s+=h.length-3}}return i}function Co(e){var t=e.markedSpans;if(t){for(var n=0;nt)&&(!r||Si(r,o.marker)<0)&&(r=o.marker)}return r}function Ao(e,t,n,r,i){var o=ye(e,t),l=Vt&&o.markedSpans;if(l)for(var a=0;a=0&&x<=0||h<=0&&x>=0)&&(h<=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?ce(u.to,n)>=0:ce(u.to,n)>0)||h>=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?ce(u.from,r)<=0:ce(u.from,r)<0)))return!0}}}function qt(e){for(var t;t=Fo(e);)e=t.find(-1,!0).line;return e}function ss(e){for(var t;t=Kn(e);)e=t.find(1,!0).line;return e}function us(e){for(var t,n;t=Kn(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function Li(e,t){var n=ye(e,t),r=qt(n);return n==r?t:f(r)}function No(e,t){if(t>e.lastLine())return t;var n=ye(e,t),r;if(!cr(e,n))return t;for(;r=Kn(n);)n=r.find(1,!0).line;return f(n)+1}function cr(e,t){var n=Vt&&t.markedSpans;if(n){for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=i,t.maxLine=r)})}var Hr=function(e,t,n){this.text=e,Do(this,t),this.height=n?n(this):1};Hr.prototype.lineNo=function(){return f(this)},Bt(Hr);function fs(e,t,n,r){e.text=t,e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null),e.order!=null&&(e.order=null),Co(e),Do(e,n);var i=r?r(e):1;i!=e.height&&Et(e,i)}function cs(e){e.parent=null,Co(e)}var ds={},hs={};function Eo(e,t){if(!e||/^\s*$/.test(e))return null;var n=t.addModeClass?hs:ds;return n[e]||(n[e]=e.replace(/\S+/g,"cm-$&"))}function Oo(e,t){var n=T("span",null,null,Y?"padding-right: .1px":null),r={pre:T("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,l=void 0;r.pos=0,r.addToken=gs,sr(e.display.measure)&&(l=Re(o,e.doc.direction))&&(r.addToken=ms(r.addToken,l)),r.map=[];var a=t!=e.display.externalMeasured&&f(o);xs(o,r,xo(e,o,a)),o.styleClasses&&(o.styleClasses.bgClass&&(r.bgClass=de(o.styleClasses.bgClass,r.bgClass||"")),o.styleClasses.textClass&&(r.textClass=de(o.styleClasses.textClass,r.textClass||""))),r.map.length==0&&r.map.push(0,0,r.content.appendChild(Rn(e.display.measure))),i==0?(t.measure.map=r.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(r.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(Y){var s=r.content.lastChild;(/\bcm-tab\b/.test(s.className)||s.querySelector&&s.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return Ye(e,"renderLine",e,t.line,r.pre),r.pre.className&&(r.textClass=de(r.pre.className,r.textClass||"")),r}function ps(e){var t=c("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function gs(e,t,n,r,i,o,l){if(t){var a=e.splitSpaces?vs(t,e.trailingSpace):t,s=e.cm.state.specialChars,u=!1,h;if(!s.test(t))e.col+=t.length,h=document.createTextNode(a),e.map.push(e.pos,e.pos+t.length,h),k&&I<9&&(u=!0),e.pos+=t.length;else{h=document.createDocumentFragment();for(var x=0;;){s.lastIndex=x;var D=s.exec(t),L=D?D.index-x:t.length-x;if(L){var H=document.createTextNode(a.slice(x,x+L));k&&I<9?h.appendChild(c("span",[H])):h.appendChild(H),e.map.push(e.pos,e.pos+L,H),e.col+=L,e.pos+=L}if(!D)break;x+=L+1;var Z=void 0;if(D[0]==" "){var ie=e.cm.options.tabSize,ae=ie-e.col%ie;Z=h.appendChild(c("span",et(ae),"cm-tab")),Z.setAttribute("role","presentation"),Z.setAttribute("cm-text"," "),e.col+=ae}else D[0]=="\r"||D[0]==` -`?(Z=h.appendChild(c("span",D[0]=="\r"?"␍":"␤","cm-invalidchar")),Z.setAttribute("cm-text",D[0]),e.col+=1):(Z=e.cm.options.specialCharPlaceholder(D[0]),Z.setAttribute("cm-text",D[0]),k&&I<9?h.appendChild(c("span",[Z])):h.appendChild(Z),e.col+=1);e.map.push(e.pos,e.pos+1,Z),e.pos++}}if(e.trailingSpace=a.charCodeAt(t.length-1)==32,n||r||i||u||o||l){var he=n||"";r&&(he+=r),i&&(he+=i);var se=c("span",[h],he,o);if(l)for(var ge in l)l.hasOwnProperty(ge)&&ge!="style"&&ge!="class"&&se.setAttribute(ge,l[ge]);return e.content.appendChild(se)}e.content.appendChild(h)}}function vs(e,t){if(e.length>1&&!/ /.test(e))return e;for(var n=t,r="",i=0;iu&&x.from<=u));D++);if(x.to>=h)return e(n,r,i,o,l,a,s);e(n,r.slice(0,x.to-u),i,o,null,a,s),o=null,r=r.slice(x.to-u),u=x.to}}}function Po(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function xs(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(!r){for(var l=1;ls||Ee.collapsed&&ke.to==s&&ke.from==s)){if(ke.to!=null&&ke.to!=s&&L>ke.to&&(L=ke.to,Z=""),Ee.className&&(H+=" "+Ee.className),Ee.css&&(D=(D?D+";":"")+Ee.css),Ee.startStyle&&ke.from==s&&(ie+=" "+Ee.startStyle),Ee.endStyle&&ke.to==L&&(ge||(ge=[])).push(Ee.endStyle,ke.to),Ee.title&&((he||(he={})).title=Ee.title),Ee.attributes)for(var Ke in Ee.attributes)(he||(he={}))[Ke]=Ee.attributes[Ke];Ee.collapsed&&(!ae||Si(ae.marker,Ee)<0)&&(ae=ke)}else ke.from>s&&L>ke.from&&(L=ke.from)}if(ge)for(var st=0;st=a)break;for(var Nt=Math.min(a,L);;){if(h){var Tt=s+h.length;if(!ae){var tt=Tt>Nt?h.slice(0,Nt-s):h;t.addToken(t,tt,x?x+H:H,ie,s+tt.length==L?Z:"",D,he)}if(Tt>=Nt){h=h.slice(Nt-s),s=Nt;break}s=Tt,ie=""}h=i.slice(o,o=n[u++]),x=Eo(n[u++],t.cm.options)}}}function Io(e,t,n){this.line=t,this.rest=us(t),this.size=this.rest?f(we(this.rest))-n+1:1,this.node=this.text=null,this.hidden=cr(e,t)}function Gn(e,t,n){for(var r=[],i,o=t;o2&&o.push((s.bottom+u.top)/2-n.top)}}o.push(n.bottom-n.top)}}function qo(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};if(e.rest){for(var r=0;rn)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function Fs(e,t){t=qt(t);var n=f(t),r=e.display.externalMeasured=new Io(e.doc,t,n);r.lineN=n;var i=r.built=Oo(e,r);return r.text=i.pre,G(e.display.lineMeasure,i.pre),r}function jo(e,t,n,r){return Qt(e,qr(e,t),n,r)}function Ai(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&tt)&&(o=s-a,i=o-1,t>=s&&(l="right")),i!=null){if(r=e[u+2],a==s&&n==(r.insertLeft?"left":"right")&&(l=n),n=="left"&&i==0)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[(u-=3)+2],l="left";if(n=="right"&&i==s-a)for(;u=0&&(n=e[i]).left==n.right;i--);return n}function Ns(e,t,n,r){var i=Uo(t.map,n,r),o=i.node,l=i.start,a=i.end,s=i.collapse,u;if(o.nodeType==3){for(var h=0;h<4;h++){for(;l&&Ne(t.line.text.charAt(i.coverStart+l));)--l;for(;i.coverStart+a0&&(s=r="right");var x;e.options.lineWrapping&&(x=o.getClientRects()).length>1?u=x[r=="right"?x.length-1:0]:u=o.getBoundingClientRect()}if(k&&I<9&&!l&&(!u||!u.left&&!u.right)){var D=o.parentNode.getClientRects()[0];D?u={left:D.left,right:D.left+Kr(e.display),top:D.top,bottom:D.bottom}:u=Ko}for(var L=u.top-t.rect.top,H=u.bottom-t.rect.top,Z=(L+H)/2,ie=t.view.measure.heights,ae=0;ae=r.text.length?(s=r.text.length,u="before"):s<=0&&(s=0,u="after"),!a)return l(u=="before"?s-1:s,u=="before");function h(H,Z,ie){var ae=a[Z],he=ae.level==1;return l(ie?H-1:H,he!=ie)}var x=lr(a,s,u),D=br,L=h(s,x,u=="before");return D!=null&&(L.other=h(s,D,u!="before")),L}function Zo(e,t){var n=0;t=Ae(e.doc,t),e.options.lineWrapping||(n=Kr(e.display)*t.ch);var r=ye(e.doc,t.line),i=er(r)+Xn(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function Ei(e,t,n,r,i){var o=B(e,t,n);return o.xRel=i,r&&(o.outside=r),o}function Oi(e,t,n){var r=e.doc;if(n+=e.display.viewOffset,n<0)return Ei(r.first,0,null,-1,-1);var i=m(r,n),o=r.first+r.size-1;if(i>o)return Ei(r.first+r.size-1,ye(r,o).text.length,null,1,1);t<0&&(t=0);for(var l=ye(r,i);;){var a=Os(e,l,i,t,n),s=as(l,a.ch+(a.xRel>0||a.outside>0?1:0));if(!s)return a;var u=s.find(1);if(u.line==i)return u;l=ye(r,i=u.line)}}function $o(e,t,n,r){r-=Ni(t);var i=t.text.length,o=Pt(function(l){return Qt(e,n,l-1).bottom<=r},i,0);return i=Pt(function(l){return Qt(e,n,l).top>r},o,i),{begin:o,end:i}}function Vo(e,t,n,r){n||(n=qr(e,t));var i=Yn(e,t,Qt(e,n,r),"line").top;return $o(e,t,n,i)}function Pi(e,t,n,r){return e.bottom<=n?!1:e.top>n?!0:(r?e.left:e.right)>t}function Os(e,t,n,r,i){i-=er(t);var o=qr(e,t),l=Ni(t),a=0,s=t.text.length,u=!0,h=Re(t,e.doc.direction);if(h){var x=(e.options.lineWrapping?Is:Ps)(e,t,n,o,h,r,i);u=x.level!=1,a=u?x.from:x.to-1,s=u?x.to:x.from-1}var D=null,L=null,H=Pt(function(Le){var ke=Qt(e,o,Le);return ke.top+=l,ke.bottom+=l,Pi(ke,r,i,!1)?(ke.top<=i&&ke.left<=r&&(D=Le,L=ke),!0):!1},a,s),Z,ie,ae=!1;if(L){var he=r-L.left=ge.bottom?1:0}return H=Mt(t.text,H,1),Ei(n,H,ie,ae,r-Z)}function Ps(e,t,n,r,i,o,l){var a=Pt(function(x){var D=i[x],L=D.level!=1;return Pi(jt(e,B(n,L?D.to:D.from,L?"before":"after"),"line",t,r),o,l,!0)},0,i.length-1),s=i[a];if(a>0){var u=s.level!=1,h=jt(e,B(n,u?s.from:s.to,u?"after":"before"),"line",t,r);Pi(h,o,l,!0)&&h.top>l&&(s=i[a-1])}return s}function Is(e,t,n,r,i,o,l){var a=$o(e,t,r,l),s=a.begin,u=a.end;/\s/.test(t.text.charAt(u-1))&&u--;for(var h=null,x=null,D=0;D=u||L.to<=s)){var H=L.level!=1,Z=Qt(e,r,H?Math.min(u,L.to)-1:Math.max(s,L.from)).right,ie=Zie)&&(h=L,x=ie)}}return h||(h=i[i.length-1]),h.fromu&&(h={from:h.from,to:u,level:h.level}),h}var Sr;function jr(e){if(e.cachedTextHeight!=null)return e.cachedTextHeight;if(Sr==null){Sr=c("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Sr.appendChild(document.createTextNode("x")),Sr.appendChild(c("br"));Sr.appendChild(document.createTextNode("x"))}G(e.measure,Sr);var n=Sr.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),F(e.measure),n||1}function Kr(e){if(e.cachedCharWidth!=null)return e.cachedCharWidth;var t=c("span","xxxxxxxxxx"),n=c("pre",[t],"CodeMirror-line-like");G(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function Ii(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,l=0;o;o=o.nextSibling,++l){var a=e.display.gutterSpecs[l].className;n[a]=o.offsetLeft+o.clientLeft+i,r[a]=o.clientWidth}return{fixedPos:zi(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function zi(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function el(e){var t=jr(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/Kr(e.display)-3);return function(i){if(cr(e.doc,i))return 0;var o=0;if(i.widgets)for(var l=0;l0&&(u=ye(e.doc,s.line).text).length==s.ch){var h=Fe(u,u.length,e.options.tabSize)-u.length;s=B(s.line,Math.max(0,Math.round((o-_o(e.display).left)/Kr(e.display))-h))}return s}function Tr(e,t){if(t>=e.display.viewTo||(t-=e.display.viewFrom,t<0))return null;for(var n=e.display.view,r=0;rt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Vt&&Li(e.doc,t)i.viewFrom?hr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)hr(e);else if(t<=i.viewFrom){var o=Jn(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):hr(e)}else if(n>=i.viewTo){var l=Jn(e,t,t,-1);l?(i.view=i.view.slice(0,l.index),i.viewTo=l.lineN):hr(e)}else{var a=Jn(e,t,t,-1),s=Jn(e,n,n+r,1);a&&s?(i.view=i.view.slice(0,a.index).concat(Gn(e,a.lineN,s.lineN)).concat(i.view.slice(s.index)),i.viewTo+=r):hr(e)}var u=i.externalMeasured;u&&(n=i.lineN&&t=r.viewTo)){var o=r.view[Tr(e,t)];if(o.node!=null){var l=o.changes||(o.changes=[]);ve(l,n)==-1&&l.push(n)}}}function hr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Jn(e,t,n,r){var i=Tr(e,t),o,l=e.display.view;if(!Vt||n==e.doc.first+e.doc.size)return{index:i,lineN:n};for(var a=e.display.viewFrom,s=0;s0){if(i==l.length-1)return null;o=a+l[i].size-t,i++}else o=a-t;t+=o,n+=o}for(;Li(e.doc,n)!=n;){if(i==(r<0?0:l.length-1))return null;n+=r*l[i-(r<0?1:0)].size,i+=r}return{index:i,lineN:n}}function zs(e,t,n){var r=e.display,i=r.view;i.length==0||t>=r.viewTo||n<=r.viewFrom?(r.view=Gn(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=Gn(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,Tr(e,n)))),r.viewTo=n}function tl(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo||s.to().line0?l:e.defaultCharWidth())+"px"}if(r.other){var a=n.appendChild(c("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));a.style.display="",a.style.left=r.other.left+"px",a.style.top=r.other.top+"px",a.style.height=(r.other.bottom-r.other.top)*.85+"px"}}function Zn(e,t){return e.top-t.top||e.left-t.left}function Bs(e,t,n){var r=e.display,i=e.doc,o=document.createDocumentFragment(),l=_o(e.display),a=l.left,s=Math.max(r.sizerWidth,wr(e)-r.sizer.offsetLeft)-l.right,u=i.direction=="ltr";function h(se,ge,Le,ke){ge<0&&(ge=0),ge=Math.round(ge),ke=Math.round(ke),o.appendChild(c("div",null,"CodeMirror-selected","position: absolute; left: "+se+`px; - top: `+ge+"px; width: "+(Le??s-se)+`px; - height: `+(ke-ge)+"px"))}function x(se,ge,Le){var ke=ye(i,se),Ee=ke.text.length,Ke,st;function Xe(tt,Ct){return Qn(e,B(se,tt),"div",ke,Ct)}function Nt(tt,Ct,ft){var nt=Vo(e,ke,null,tt),rt=Ct=="ltr"==(ft=="after")?"left":"right",Ze=ft=="after"?nt.begin:nt.end-(/\s/.test(ke.text.charAt(nt.end-1))?2:1);return Xe(Ze,rt)[rt]}var Tt=Re(ke,i.direction);return or(Tt,ge||0,Le??Ee,function(tt,Ct,ft,nt){var rt=ft=="ltr",Ze=Xe(tt,rt?"left":"right"),Dt=Xe(Ct-1,rt?"right":"left"),nn=ge==null&&tt==0,yr=Le==null&&Ct==Ee,vt=nt==0,Jt=!Tt||nt==Tt.length-1;if(Dt.top-Ze.top<=3){var ut=(u?nn:yr)&&vt,co=(u?yr:nn)&&Jt,ir=ut?a:(rt?Ze:Dt).left,Ar=co?s:(rt?Dt:Ze).right;h(ir,Ze.top,Ar-ir,Ze.bottom)}else{var Nr,bt,on,ho;rt?(Nr=u&&nn&&vt?a:Ze.left,bt=u?s:Nt(tt,ft,"before"),on=u?a:Nt(Ct,ft,"after"),ho=u&&yr&&Jt?s:Dt.right):(Nr=u?Nt(tt,ft,"before"):a,bt=!u&&nn&&vt?s:Ze.right,on=!u&&yr&&Jt?a:Dt.left,ho=u?Nt(Ct,ft,"after"):s),h(Nr,Ze.top,bt-Nr,Ze.bottom),Ze.bottom0?t.blinker=setInterval(function(){e.hasFocus()||Ur(e),t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function nl(e){e.hasFocus()||(e.display.input.focus(),e.state.focused||_i(e))}function Hi(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,e.state.focused&&Ur(e))},100)}function _i(e,t){e.state.delayingBlurEvent&&!e.state.draggingText&&(e.state.delayingBlurEvent=!1),e.options.readOnly!="nocursor"&&(e.state.focused||(Ye(e,"focus",e,t),e.state.focused=!0,j(e.display.wrapper,"CodeMirror-focused"),!e.curOp&&e.display.selForContextMenu!=e.doc.sel&&(e.display.input.reset(),Y&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),Wi(e))}function Ur(e,t){e.state.delayingBlurEvent||(e.state.focused&&(Ye(e,"blur",e,t),e.state.focused=!1,V(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function $n(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=Math.max(0,t.scroller.getBoundingClientRect().top),i=t.lineDiv.getBoundingClientRect().top,o=0,l=0;l.005||L<-.005)&&(ie.display.sizerWidth){var Z=Math.ceil(h/Kr(e.display));Z>e.display.maxLineLength&&(e.display.maxLineLength=Z,e.display.maxLine=a.line,e.display.maxLineChanged=!0)}}}Math.abs(o)>2&&(t.scroller.scrollTop+=o)}function il(e){if(e.widgets)for(var t=0;t=l&&(o=m(t,er(ye(t,s))-e.wrapper.clientHeight),l=s)}return{from:o,to:Math.max(l,o+1)}}function Rs(e,t){if(!Qe(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null,o=n.wrapper.ownerDocument;if(t.top+r.top<0?i=!0:t.bottom+r.top>(o.defaultView.innerHeight||o.documentElement.clientHeight)&&(i=!1),i!=null&&!O){var l=c("div","​",null,`position: absolute; - top: `+(t.top-n.viewOffset-Xn(e.display))+`px; - height: `+(t.bottom-t.top+Yt(e)+n.barHeight)+`px; - left: `+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(l),l.scrollIntoView(i),e.display.lineSpace.removeChild(l)}}}function Ws(e,t,n,r){r==null&&(r=0);var i;!e.options.lineWrapping&&t==n&&(n=t.sticky=="before"?B(t.line,t.ch+1,"before"):t,t=t.ch?B(t.line,t.sticky=="before"?t.ch-1:t.ch,"after"):t);for(var o=0;o<5;o++){var l=!1,a=jt(e,t),s=!n||n==t?a:jt(e,n);i={left:Math.min(a.left,s.left),top:Math.min(a.top,s.top)-r,right:Math.max(a.left,s.left),bottom:Math.max(a.bottom,s.bottom)+r};var u=qi(e,i),h=e.doc.scrollTop,x=e.doc.scrollLeft;if(u.scrollTop!=null&&(xn(e,u.scrollTop),Math.abs(e.doc.scrollTop-h)>1&&(l=!0)),u.scrollLeft!=null&&(Cr(e,u.scrollLeft),Math.abs(e.doc.scrollLeft-x)>1&&(l=!0)),!l)break}return i}function Hs(e,t){var n=qi(e,t);n.scrollTop!=null&&xn(e,n.scrollTop),n.scrollLeft!=null&&Cr(e,n.scrollLeft)}function qi(e,t){var n=e.display,r=jr(e.display);t.top<0&&(t.top=0);var i=e.curOp&&e.curOp.scrollTop!=null?e.curOp.scrollTop:n.scroller.scrollTop,o=Fi(e),l={};t.bottom-t.top>o&&(t.bottom=t.top+o);var a=e.doc.height+Mi(n),s=t.topa-r;if(t.topi+o){var h=Math.min(t.top,(u?a:t.bottom)-o);h!=i&&(l.scrollTop=h)}var x=e.options.fixedGutter?0:n.gutters.offsetWidth,D=e.curOp&&e.curOp.scrollLeft!=null?e.curOp.scrollLeft:n.scroller.scrollLeft-x,L=wr(e)-n.gutters.offsetWidth,H=t.right-t.left>L;return H&&(t.right=t.left+L),t.left<10?l.scrollLeft=0:t.leftL+D-3&&(l.scrollLeft=t.right+(H?0:10)-L),l}function ji(e,t){t!=null&&(ei(e),e.curOp.scrollTop=(e.curOp.scrollTop==null?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Gr(e){ei(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function mn(e,t,n){(t!=null||n!=null)&&ei(e),t!=null&&(e.curOp.scrollLeft=t),n!=null&&(e.curOp.scrollTop=n)}function _s(e,t){ei(e),e.curOp.scrollToPos=t}function ei(e){var t=e.curOp.scrollToPos;if(t){e.curOp.scrollToPos=null;var n=Zo(e,t.from),r=Zo(e,t.to);ol(e,n,r,t.margin)}}function ol(e,t,n,r){var i=qi(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});mn(e,i.scrollLeft,i.scrollTop)}function xn(e,t){Math.abs(e.doc.scrollTop-t)<2||(_||Ui(e,{top:t}),ll(e,t,!0),_&&Ui(e),kn(e,100))}function ll(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),!(e.display.scroller.scrollTop==t&&!n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Cr(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),!((n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r)&&(e.doc.scrollLeft=t,cl(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function yn(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Mi(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Yt(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}var Dr=function(e,t,n){this.cm=n;var r=this.vert=c("div",[c("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=c("div",[c("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),Se(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),Se(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,k&&I<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Dr.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(r==0&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Dr.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Dr.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Dr.prototype.zeroWidthHack=function(){var e=z&&!ue?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.visibility=this.vert.style.visibility="hidden",this.disableHoriz=new Ce,this.disableVert=new Ce},Dr.prototype.enableZeroWidthBar=function(e,t,n){e.style.visibility="";function r(){var i=e.getBoundingClientRect(),o=n=="vert"?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1);o!=e?e.style.visibility="hidden":t.set(1e3,r)}t.set(1e3,r)},Dr.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var bn=function(){};bn.prototype.update=function(){return{bottom:0,right:0}},bn.prototype.setScrollLeft=function(){},bn.prototype.setScrollTop=function(){},bn.prototype.clear=function(){};function Xr(e,t){t||(t=yn(e));var n=e.display.barWidth,r=e.display.barHeight;al(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&$n(e),al(e,yn(e)),n=e.display.barWidth,r=e.display.barHeight}function al(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}var sl={native:Dr,null:bn};function ul(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&V(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new sl[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),Se(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){n=="horizontal"?Cr(e,t):xn(e,t)},e),e.display.scrollbars.addClass&&j(e.display.wrapper,e.display.scrollbars.addClass)}var qs=0;function Mr(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++qs,markArrays:null},ys(e.curOp)}function Fr(e){var t=e.curOp;t&&ks(t,function(n){for(var r=0;r=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ti(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function Us(e){e.updatedDisplay=e.mustUpdate&&Ki(e.cm,e.update)}function Gs(e){var t=e.cm,n=t.display;e.updatedDisplay&&$n(t),e.barMeasure=yn(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=jo(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Yt(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-wr(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function Xs(e){var t=e.cm;e.adjustWidthTo!=null&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft=e.display.viewTo)){var n=+new Date+e.options.workTime,r=fn(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var l=o.styles,a=o.text.length>e.options.maxHighlightLength?Gt(t.mode,r.state):null,s=mo(e,o,r,!0);a&&(r.state=a),o.styles=s.styles;var u=o.styleClasses,h=s.classes;h?o.styleClasses=h:u&&(o.styleClasses=null);for(var x=!l||l.length!=o.styles.length||u!=h&&(!u||!h||u.bgClass!=h.bgClass||u.textClass!=h.textClass),D=0;!x&&Dn)return kn(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&At(e,function(){for(var o=0;o=n.viewFrom&&t.visible.to<=n.viewTo&&(n.updateLineNumbers==null||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&tl(e)==0)return!1;dl(e)&&(hr(e),t.dims=Ii(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),l=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFroml&&n.viewTo-l<20&&(l=Math.min(i,n.viewTo)),Vt&&(o=Li(e.doc,o),l=No(e.doc,l));var a=o!=n.viewFrom||l!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;zs(e,o,l),n.viewOffset=er(ye(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var s=tl(e);if(!a&&s==0&&!t.force&&n.renderedView==n.view&&(n.updateLineNumbers==null||n.updateLineNumbers>=n.viewTo))return!1;var u=Zs(e);return s>4&&(n.lineDiv.style.display="none"),Vs(e,n.updateLineNumbers,t.dims),s>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,$s(u),F(n.cursorDiv),F(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,a&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,kn(e,400)),n.updateLineNumbers=null,!0}function fl(e,t){for(var n=t.viewport,r=!0;;r=!1){if(!r||!e.options.lineWrapping||t.oldDisplayWidth==wr(e)){if(n&&n.top!=null&&(n={top:Math.min(e.doc.height+Mi(e.display)-Fi(e),n.top)}),t.visible=Vn(e.display,e.doc,n),t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break}else r&&(t.visible=Vn(e.display,e.doc,n));if(!Ki(e,t))break;$n(e);var i=yn(e);vn(e),Xr(e,i),Xi(e,i),t.force=!1}t.signal(e,"update",e),(e.display.viewFrom!=e.display.reportedViewFrom||e.display.viewTo!=e.display.reportedViewTo)&&(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Ui(e,t){var n=new ti(e,t);if(Ki(e,n)){$n(e),fl(e,n);var r=yn(e);vn(e),Xr(e,r),Xi(e,r),n.finish()}}function Vs(e,t,n){var r=e.display,i=e.options.lineNumbers,o=r.lineDiv,l=o.firstChild;function a(H){var Z=H.nextSibling;return Y&&z&&e.display.currentWheelTarget==H?H.style.display="none":H.parentNode.removeChild(H),Z}for(var s=r.view,u=r.viewFrom,h=0;h-1&&(L=!1),zo(e,x,u,n)),L&&(F(x.lineNumber),x.lineNumber.appendChild(document.createTextNode(re(e.options,u)))),l=x.node.nextSibling}u+=x.size}for(;l;)l=a(l)}function Gi(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",ot(e,"gutterChanged",e)}function Xi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Yt(e)+"px"}function cl(e){var t=e.display,n=t.view;if(!(!t.alignWidgets&&(!t.gutters.firstChild||!e.options.fixedGutter))){for(var r=zi(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",l=0;l=105&&(i.wrapper.style.clipPath="inset(0px)"),i.wrapper.setAttribute("translate","no"),k&&I<8&&(i.gutters.style.zIndex=-1,i.scroller.style.paddingRight=0),!Y&&!(_&&N)&&(i.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(i.wrapper):e(i.wrapper)),i.viewFrom=i.viewTo=t.first,i.reportedViewFrom=i.reportedViewTo=t.first,i.view=[],i.renderedView=null,i.externalMeasured=null,i.viewOffset=0,i.lastWrapHeight=i.lastWrapWidth=0,i.updateLineNumbers=null,i.nativeBarWidth=i.barHeight=i.barWidth=0,i.scrollbarsClipped=!1,i.lineNumWidth=i.lineNumInnerWidth=i.lineNumChars=null,i.alignWidgets=!1,i.cachedCharWidth=i.cachedTextHeight=i.cachedPaddingH=null,i.maxLine=null,i.maxLineLength=0,i.maxLineChanged=!1,i.wheelDX=i.wheelDY=i.wheelStartX=i.wheelStartY=null,i.shift=!1,i.selForContextMenu=null,i.activeTouch=null,i.gutterSpecs=Yi(r.gutters,r.lineNumbers),hl(i),n.init(i)}var ri=0,rr=null;k?rr=-.53:_?rr=15:S?rr=-.7:$&&(rr=-1/3);function pl(e){var t=e.wheelDeltaX,n=e.wheelDeltaY;return t==null&&e.detail&&e.axis==e.HORIZONTAL_AXIS&&(t=e.detail),n==null&&e.detail&&e.axis==e.VERTICAL_AXIS?n=e.detail:n==null&&(n=e.wheelDelta),{x:t,y:n}}function tu(e){var t=pl(e);return t.x*=rr,t.y*=rr,t}function gl(e,t){S&&R==102&&(e.display.chromeScrollHack==null?e.display.sizer.style.pointerEvents="none":clearTimeout(e.display.chromeScrollHack),e.display.chromeScrollHack=setTimeout(function(){e.display.chromeScrollHack=null,e.display.sizer.style.pointerEvents=""},100));var n=pl(t),r=n.x,i=n.y,o=rr;t.deltaMode===0&&(r=t.deltaX,i=t.deltaY,o=1);var l=e.display,a=l.scroller,s=a.scrollWidth>a.clientWidth,u=a.scrollHeight>a.clientHeight;if(r&&s||i&&u){if(i&&z&&Y){e:for(var h=t.target,x=l.view;h!=a;h=h.parentNode)for(var D=0;D=0&&ce(e,r.to())<=0)return n}return-1};var He=function(e,t){this.anchor=e,this.head=t};He.prototype.from=function(){return Wr(this.anchor,this.head)},He.prototype.to=function(){return wt(this.anchor,this.head)},He.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch};function Kt(e,t,n){var r=e&&e.options.selectionsMayTouch,i=t[n];t.sort(function(D,L){return ce(D.from(),L.from())}),n=ve(t,i);for(var o=1;o0:s>=0){var u=Wr(a.from(),l.from()),h=wt(a.to(),l.to()),x=a.empty()?l.from()==l.head:a.from()==a.head;o<=n&&--n,t.splice(--o,2,new He(x?h:u,x?u:h))}}return new Ot(t,n)}function pr(e,t){return new Ot([new He(e,t||e)],0)}function gr(e){return e.text?B(e.from.line+e.text.length-1,we(e.text).length+(e.text.length==1?e.from.ch:0)):e.to}function vl(e,t){if(ce(e,t.from)<0)return e;if(ce(e,t.to)<=0)return gr(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=gr(t).ch-t.to.ch),B(n,r)}function Qi(e,t){for(var n=[],r=0;r1&&e.remove(a.line+1,H-1),e.insert(a.line+1,ae)}ot(e,"change",e,t)}function vr(e,t,n){function r(i,o,l){if(i.linked)for(var a=0;a1&&!e.done[e.done.length-2].ranges)return e.done.pop(),we(e.done)}function wl(e,t,n,r){var i=e.history;i.undone.length=0;var o=+new Date,l,a;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&(t.origin.charAt(0)=="+"&&i.lastModTime>o-(e.cm?e.cm.options.historyEventDelay:500)||t.origin.charAt(0)=="*"))&&(l=iu(i,i.lastOp==r)))a=we(l.changes),ce(t.from,t.to)==0&&ce(t.from,a.to)==0?a.to=gr(t):l.changes.push($i(e,t));else{var s=we(i.done);for((!s||!s.ranges)&&ii(e.sel,i.done),l={changes:[$i(e,t)],generation:i.generation},i.done.push(l);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=o,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||Ye(e,"historyAdded")}function ou(e,t,n,r){var i=t.charAt(0);return i=="*"||i=="+"&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function lu(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||ou(e,o,we(i.done),t))?i.done[i.done.length-1]=t:ii(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&r.clearRedo!==!1&&kl(i.undone)}function ii(e,t){var n=we(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Sl(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(l){l.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=l.markedSpans),++o})}function au(e){if(!e)return null;for(var t,n=0;n-1&&(we(a)[x]=u[x],delete u[x])}}return r}function Vi(e,t,n,r){if(r){var i=e.anchor;if(n){var o=ce(t,i)<0;o!=ce(n,i)<0?(i=t,t=n):o!=ce(t,n)<0&&(t=n)}return new He(i,t)}else return new He(n||t,t)}function oi(e,t,n,r,i){i==null&&(i=e.cm&&(e.cm.display.shift||e.extend)),gt(e,new Ot([Vi(e.sel.primary(),t,n,i)],0),r)}function Tl(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:a.to>t.ch))){if(i&&(Ye(s,"beforeCursorEnter"),s.explicitlyCleared))if(o.markedSpans){--l;continue}else break;if(!s.atomic)continue;if(n){var x=s.find(r<0?1:-1),D=void 0;if((r<0?h:u)&&(x=Nl(e,x,-r,x&&x.line==t.line?o:null)),x&&x.line==t.line&&(D=ce(x,n))&&(r<0?D<0:D>0))return Qr(e,x,t,r,i)}var L=s.find(r<0?-1:1);return(r<0?u:h)&&(L=Nl(e,L,r,L.line==t.line?o:null)),L?Qr(e,L,t,r,i):null}}return t}function ai(e,t,n,r,i){var o=r||1,l=Qr(e,t,n,o,i)||!i&&Qr(e,t,n,o,!0)||Qr(e,t,n,-o,i)||!i&&Qr(e,t,n,-o,!0);return l||(e.cantEdit=!0,B(e.first,0))}function Nl(e,t,n,r){return n<0&&t.ch==0?t.line>e.first?Ae(e,B(t.line-1)):null:n>0&&t.ch==(r||ye(e,t.line)).text.length?t.line=0;--i)Pl(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else Pl(e,t)}}function Pl(e,t){if(!(t.text.length==1&&t.text[0]==""&&ce(t.from,t.to)==0)){var n=Qi(e,t);wl(e,t,n,e.cm?e.cm.curOp.id:NaN),Ln(e,t,n,wi(e,t));var r=[];vr(e,function(i,o){!o&&ve(r,i.history)==-1&&(Rl(i.history,t),r.push(i.history)),Ln(i,t,null,wi(i,t))})}}function si(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!(r&&!n)){for(var i=e.history,o,l=e.sel,a=t=="undo"?i.done:i.undone,s=t=="undo"?i.undone:i.done,u=0;u=0;--L){var H=D(L);if(H)return H.v}}}}function Il(e,t){if(t!=0&&(e.first+=t,e.sel=new Ot(Ie(e.sel.ranges,function(i){return new He(B(i.anchor.line+t,i.anchor.ch),B(i.head.line+t,i.head.ch))}),e.sel.primIndex),e.cm)){St(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:B(o,ye(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=$t(e,t.from,t.to),n||(n=Qi(e,t)),e.cm?fu(e.cm,t,r):Zi(e,t,r),li(e,n,$e),e.cantEdit&&ai(e,B(e.firstLine(),0))&&(e.cantEdit=!1)}}function fu(e,t,n){var r=e.doc,i=e.display,o=t.from,l=t.to,a=!1,s=o.line;e.options.lineWrapping||(s=f(qt(ye(r,o.line))),r.iter(s,l.line+1,function(L){if(L==i.maxLine)return a=!0,!0})),r.sel.contains(t.from,t.to)>-1&&It(e),Zi(r,t,n,el(e)),e.options.lineWrapping||(r.iter(s,o.line+t.text.length,function(L){var H=Un(L);H>i.maxLineLength&&(i.maxLine=L,i.maxLineLength=H,i.maxLineChanged=!0,a=!1)}),a&&(e.curOp.updateMaxLine=!0)),Va(r,o.line),kn(e,400);var u=t.text.length-(l.line-o.line)-1;t.full?St(e):o.line==l.line&&t.text.length==1&&!xl(e.doc,t)?dr(e,o.line,"text"):St(e,o.line,l.line+1,u);var h=Ft(e,"changes"),x=Ft(e,"change");if(x||h){var D={from:o,to:l,text:t.text,removed:t.removed,origin:t.origin};x&&ot(e,"change",e,D),h&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(D)}e.display.selForContextMenu=null}function Zr(e,t,n,r,i){var o;r||(r=n),ce(r,n)<0&&(o=[r,n],n=o[0],r=o[1]),typeof t=="string"&&(t=e.splitLines(t)),Jr(e,{from:n,to:r,text:t,origin:i})}function zl(e,t,n,r){n1||!(this.children[0]instanceof Cn))){var a=[];this.collapse(a),this.children=[new Cn(a)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var l=i.lines.length%25+25,a=l;a10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;re.display.maxLineLength&&(e.display.maxLine=u,e.display.maxLineLength=h,e.display.maxLineChanged=!0)}r!=null&&e&&this.collapsed&&St(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&Fl(e.doc)),e&&ot(e,"markerCleared",e,this,r,i),t&&Fr(e),this.parent&&this.parent.clear()}},mr.prototype.find=function(e,t){e==null&&this.type=="bookmark"&&(e=1);for(var n,r,i=0;i0||l==0&&o.clearWhenEmpty!==!1)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=T("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Ao(e,t.line,t,n,o)||t.line!=n.line&&Ao(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");ts()}o.addToHistory&&wl(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var a=t.line,s=e.cm,u;if(e.iter(a,n.line+1,function(x){s&&o.collapsed&&!s.options.lineWrapping&&qt(x)==s.display.maxLine&&(u=!0),o.collapsed&&a!=t.line&&Et(x,0),ns(x,new _n(o,a==t.line?t.ch:null,a==n.line?n.ch:null),e.cm&&e.cm.curOp),++a}),o.collapsed&&e.iter(t.line,n.line+1,function(x){cr(e,x)&&Et(x,0)}),o.clearOnEnter&&Se(o,"beforeCursorEnter",function(){return o.clear()}),o.readOnly&&(es(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++Hl,o.atomic=!0),s){if(u&&(s.curOp.updateMaxLine=!0),o.collapsed)St(s,t.line,n.line+1);else if(o.className||o.startStyle||o.endStyle||o.css||o.attributes||o.title)for(var h=t.line;h<=n.line;h++)dr(s,h,"text");o.atomic&&Fl(s.doc),ot(s,"markerAdded",s,o)}return o}var Fn=function(e,t){this.markers=e,this.primary=t;for(var n=0;n=0;s--)Jr(this,r[s]);a?Dl(this,a):this.cm&&Gr(this.cm)}),undo:at(function(){si(this,"undo")}),redo:at(function(){si(this,"redo")}),undoSelection:at(function(){si(this,"undo",!0)}),redoSelection:at(function(){si(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=Ae(this,e),t=Ae(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var l=o.markedSpans;if(l)for(var a=0;a=s.to||s.from==null&&i!=e.line||s.from!=null&&i==t.line&&s.from>=t.ch)&&(!n||n(s.marker))&&r.push(s.marker.parent||s.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n}),Ae(this,B(n,t))},indexFromPos:function(e){e=Ae(this,e);var t=e.ch;if(e.linet&&(t=e.from),e.to!=null&&e.to-1){t.state.draggingText(e),setTimeout(function(){return t.display.input.focus()},20);return}try{var h=e.dataTransfer.getData("Text");if(h){var x;if(t.state.draggingText&&!t.state.draggingText.copy&&(x=t.listSelections()),li(t.doc,pr(n,n)),x)for(var D=0;D=0;a--)Zr(e.doc,"",r[a].from,r[a].to,"+delete");Gr(e)})}function to(e,t,n){var r=Mt(e.text,t+n,n);return r<0||r>e.text.length?null:r}function ro(e,t,n){var r=to(e,t.ch,n);return r==null?null:new B(t.line,r,n<0?"after":"before")}function no(e,t,n,r,i){if(e){t.doc.direction=="rtl"&&(i=-i);var o=Re(n,t.doc.direction);if(o){var l=i<0?we(o):o[0],a=i<0==(l.level==1),s=a?"after":"before",u;if(l.level>0||t.doc.direction=="rtl"){var h=qr(t,n);u=i<0?n.text.length-1:0;var x=Qt(t,h,u).top;u=Pt(function(D){return Qt(t,h,D).top==x},i<0==(l.level==1)?l.from:l.to-1,u),s=="before"&&(u=to(n,u,1))}else u=i<0?l.to:l.from;return new B(r,u,s)}}return new B(r,i<0?n.text.length:0,i<0?"before":"after")}function Lu(e,t,n,r){var i=Re(t,e.doc.direction);if(!i)return ro(t,n,r);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=lr(i,n.ch,n.sticky),l=i[o];if(e.doc.direction=="ltr"&&l.level%2==0&&(r>0?l.to>n.ch:l.from=l.from&&D>=h.begin)){var L=x?"before":"after";return new B(n.line,D,L)}}var H=function(ae,he,se){for(var ge=function(Ke,st){return st?new B(n.line,a(Ke,1),"before"):new B(n.line,Ke,"after")};ae>=0&&ae0==(Le.level!=1),Ee=ke?se.begin:a(se.end,-1);if(Le.from<=Ee&&Ee0?h.end:a(h.begin,-1);return ie!=null&&!(r>0&&ie==t.text.length)&&(Z=H(r>0?0:i.length-1,r,u(ie)),Z)?Z:null}var En={selectAll:El,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),$e)},killLine:function(e){return en(e,function(t){if(t.empty()){var n=ye(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line0)i=new B(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),B(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var l=ye(e.doc,i.line-1).text;l&&(i=new B(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+l.charAt(l.length-1),B(i.line-1,l.length-1),i,"+transpose"))}}n.push(new He(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return At(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;re&&ce(t,this.pos)==0&&n==this.button};var Pn,In;function Nu(e,t){var n=+new Date;return In&&In.compare(n,e,t)?(Pn=In=null,"triple"):Pn&&Pn.compare(n,e,t)?(In=new oo(n,e,t),Pn=null,"double"):(Pn=new oo(n,e,t),In=null,"single")}function ra(e){var t=this,n=t.display;if(!(Qe(t,e)||n.activeTouch&&n.input.supportsTouch())){if(n.input.ensurePolled(),n.shift=e.shiftKey,tr(n,e)){Y||(n.scroller.draggable=!1,setTimeout(function(){return n.scroller.draggable=!0},100));return}if(!lo(t,e)){var r=Lr(t,e),i=Rt(e),o=r?Nu(r,i):"single";le(t).focus(),i==1&&t.state.selectingText&&t.state.selectingText(e),!(r&&Eu(t,i,r,o,e))&&(i==1?r?Pu(t,r,o,e):ln(e)==n.scroller&&pt(e):i==2?(r&&oi(t.doc,r),setTimeout(function(){return n.input.focus()},20)):i==3&&(J?t.display.input.onContextMenu(e):Hi(t)))}}}function Eu(e,t,n,r,i){var o="Click";return r=="double"?o="Double"+o:r=="triple"&&(o="Triple"+o),o=(t==1?"Left":t==2?"Middle":"Right")+o,On(e,Xl(o,i),i,function(l){if(typeof l=="string"&&(l=En[l]),!l)return!1;var a=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),a=l(e,n)!=qe}finally{e.state.suppressEdits=!1}return a})}function Ou(e,t,n){var r=e.getOption("configureMouse"),i=r?r(e,t,n):{};if(i.unit==null){var o=X?n.shiftKey&&n.metaKey:n.altKey;i.unit=o?"rectangle":t=="single"?"char":t=="double"?"word":"line"}return(i.extend==null||e.doc.extend)&&(i.extend=e.doc.extend||n.shiftKey),i.addNew==null&&(i.addNew=z?n.metaKey:n.ctrlKey),i.moveOnDrag==null&&(i.moveOnDrag=!(z?n.altKey:n.ctrlKey)),i}function Pu(e,t,n,r){k?setTimeout(xe(nl,e),0):e.curOp.focus=y(fe(e));var i=Ou(e,n,r),o=e.doc.sel,l;e.options.dragDrop&&xi&&!e.isReadOnly()&&n=="single"&&(l=o.contains(t))>-1&&(ce((l=o.ranges[l]).from(),t)<0||t.xRel>0)&&(ce(l.to(),t)>0||t.xRel<0)?Iu(e,r,t,i):zu(e,r,t,i)}function Iu(e,t,n,r){var i=e.display,o=!1,l=lt(e,function(u){Y&&(i.scroller.draggable=!1),e.state.draggingText=!1,e.state.delayingBlurEvent&&(e.hasFocus()?e.state.delayingBlurEvent=!1:Hi(e)),ht(i.wrapper.ownerDocument,"mouseup",l),ht(i.wrapper.ownerDocument,"mousemove",a),ht(i.scroller,"dragstart",s),ht(i.scroller,"drop",l),o||(pt(u),r.addNew||oi(e.doc,n,null,null,r.extend),Y&&!$||k&&I==9?setTimeout(function(){i.wrapper.ownerDocument.body.focus({preventScroll:!0}),i.input.focus()},20):i.input.focus())}),a=function(u){o=o||Math.abs(t.clientX-u.clientX)+Math.abs(t.clientY-u.clientY)>=10},s=function(){return o=!0};Y&&(i.scroller.draggable=!0),e.state.draggingText=l,l.copy=!r.moveOnDrag,Se(i.wrapper.ownerDocument,"mouseup",l),Se(i.wrapper.ownerDocument,"mousemove",a),Se(i.scroller,"dragstart",s),Se(i.scroller,"drop",l),e.state.delayingBlurEvent=!0,setTimeout(function(){return i.input.focus()},20),i.scroller.dragDrop&&i.scroller.dragDrop()}function na(e,t,n){if(n=="char")return new He(t,t);if(n=="word")return e.findWordAt(t);if(n=="line")return new He(B(t.line,0),Ae(e.doc,B(t.line+1,0)));var r=n(e,t);return new He(r.from,r.to)}function zu(e,t,n,r){k&&Hi(e);var i=e.display,o=e.doc;pt(t);var l,a,s=o.sel,u=s.ranges;if(r.addNew&&!r.extend?(a=o.sel.contains(n),a>-1?l=u[a]:l=new He(n,n)):(l=o.sel.primary(),a=o.sel.primIndex),r.unit=="rectangle")r.addNew||(l=new He(n,n)),n=Lr(e,t,!0,!0),a=-1;else{var h=na(e,n,r.unit);r.extend?l=Vi(l,h.anchor,h.head,r.extend):l=h}r.addNew?a==-1?(a=u.length,gt(o,Kt(e,u.concat([l]),a),{scroll:!1,origin:"*mouse"})):u.length>1&&u[a].empty()&&r.unit=="char"&&!r.extend?(gt(o,Kt(e,u.slice(0,a).concat(u.slice(a+1)),0),{scroll:!1,origin:"*mouse"}),s=o.sel):eo(o,a,l,dt):(a=0,gt(o,new Ot([l],0),dt),s=o.sel);var x=n;function D(se){if(ce(x,se)!=0)if(x=se,r.unit=="rectangle"){for(var ge=[],Le=e.options.tabSize,ke=Fe(ye(o,n.line).text,n.ch,Le),Ee=Fe(ye(o,se.line).text,se.ch,Le),Ke=Math.min(ke,Ee),st=Math.max(ke,Ee),Xe=Math.min(n.line,se.line),Nt=Math.min(e.lastLine(),Math.max(n.line,se.line));Xe<=Nt;Xe++){var Tt=ye(o,Xe).text,tt=_e(Tt,Ke,Le);Ke==st?ge.push(new He(B(Xe,tt),B(Xe,tt))):Tt.length>tt&&ge.push(new He(B(Xe,tt),B(Xe,_e(Tt,st,Le))))}ge.length||ge.push(new He(n,n)),gt(o,Kt(e,s.ranges.slice(0,a).concat(ge),a),{origin:"*mouse",scroll:!1}),e.scrollIntoView(se)}else{var Ct=l,ft=na(e,se,r.unit),nt=Ct.anchor,rt;ce(ft.anchor,nt)>0?(rt=ft.head,nt=Wr(Ct.from(),ft.anchor)):(rt=ft.anchor,nt=wt(Ct.to(),ft.head));var Ze=s.ranges.slice(0);Ze[a]=Bu(e,new He(Ae(o,nt),rt)),gt(o,Kt(e,Ze,a),dt)}}var L=i.wrapper.getBoundingClientRect(),H=0;function Z(se){var ge=++H,Le=Lr(e,se,!0,r.unit=="rectangle");if(Le)if(ce(Le,x)!=0){e.curOp.focus=y(fe(e)),D(Le);var ke=Vn(i,o);(Le.line>=ke.to||Le.lineL.bottom?20:0;Ee&&setTimeout(lt(e,function(){H==ge&&(i.scroller.scrollTop+=Ee,Z(se))}),50)}}function ie(se){e.state.selectingText=!1,H=1/0,se&&(pt(se),i.input.focus()),ht(i.wrapper.ownerDocument,"mousemove",ae),ht(i.wrapper.ownerDocument,"mouseup",he),o.history.lastSelOrigin=null}var ae=lt(e,function(se){se.buttons===0||!Rt(se)?ie(se):Z(se)}),he=lt(e,ie);e.state.selectingText=he,Se(i.wrapper.ownerDocument,"mousemove",ae),Se(i.wrapper.ownerDocument,"mouseup",he)}function Bu(e,t){var n=t.anchor,r=t.head,i=ye(e.doc,n.line);if(ce(n,r)==0&&n.sticky==r.sticky)return t;var o=Re(i);if(!o)return t;var l=lr(o,n.ch,n.sticky),a=o[l];if(a.from!=n.ch&&a.to!=n.ch)return t;var s=l+(a.from==n.ch==(a.level!=1)?0:1);if(s==0||s==o.length)return t;var u;if(r.line!=n.line)u=(r.line-n.line)*(e.doc.direction=="ltr"?1:-1)>0;else{var h=lr(o,r.ch,r.sticky),x=h-l||(r.ch-n.ch)*(a.level==1?-1:1);h==s-1||h==s?u=x<0:u=x>0}var D=o[s+(u?-1:0)],L=u==(D.level==1),H=L?D.from:D.to,Z=L?"after":"before";return n.ch==H&&n.sticky==Z?t:new He(new B(n.line,H,Z),r)}function ia(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch{return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&pt(t);var l=e.display,a=l.lineDiv.getBoundingClientRect();if(o>a.bottom||!Ft(e,n))return kt(t);o-=a.top-l.viewOffset;for(var s=0;s=i){var h=m(e.doc,o),x=e.display.gutterSpecs[s];return Ye(e,n,e,h,x.className,t),kt(t)}}}function lo(e,t){return ia(e,t,"gutterClick",!0)}function oa(e,t){tr(e.display,t)||Ru(e,t)||Qe(e,t,"contextmenu")||J||e.display.input.onContextMenu(t)}function Ru(e,t){return Ft(e,"gutterContextMenu")?ia(e,t,"gutterContextMenu",!1):!1}function la(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),gn(e)}var tn={toString:function(){return"CodeMirror.Init"}},aa={},di={};function Wu(e){var t=e.optionHandlers;function n(r,i,o,l){e.defaults[r]=i,o&&(t[r]=l?function(a,s,u){u!=tn&&o(a,s,u)}:o)}e.defineOption=n,e.Init=tn,n("value","",function(r,i){return r.setValue(i)},!0),n("mode",null,function(r,i){r.doc.modeOption=i,Ji(r)},!0),n("indentUnit",2,Ji,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,function(r){Sn(r),gn(r),St(r)},!0),n("lineSeparator",null,function(r,i){if(r.doc.lineSep=i,!!i){var o=[],l=r.doc.first;r.doc.iter(function(s){for(var u=0;;){var h=s.text.indexOf(i,u);if(h==-1)break;u=h+i.length,o.push(B(l,h))}l++});for(var a=o.length-1;a>=0;a--)Zr(r.doc,i,o[a],B(o[a].line,o[a].ch+i.length))}}),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g,function(r,i,o){r.state.specialChars=new RegExp(i.source+(i.test(" ")?"":"| "),"g"),o!=tn&&r.refresh()}),n("specialCharPlaceholder",ps,function(r){return r.refresh()},!0),n("electricChars",!0),n("inputStyle",N?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),n("spellcheck",!1,function(r,i){return r.getInputField().spellcheck=i},!0),n("autocorrect",!1,function(r,i){return r.getInputField().autocorrect=i},!0),n("autocapitalize",!1,function(r,i){return r.getInputField().autocapitalize=i},!0),n("rtlMoveVisually",!q),n("wholeLineUpdateBefore",!0),n("theme","default",function(r){la(r),wn(r)},!0),n("keyMap","default",function(r,i,o){var l=fi(i),a=o!=tn&&fi(o);a&&a.detach&&a.detach(r,l),l.attach&&l.attach(r,a||null)}),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,_u,!0),n("gutters",[],function(r,i){r.display.gutterSpecs=Yi(i,r.options.lineNumbers),wn(r)},!0),n("fixedGutter",!0,function(r,i){r.display.gutters.style.left=i?zi(r.display)+"px":"0",r.refresh()},!0),n("coverGutterNextToScrollbar",!1,function(r){return Xr(r)},!0),n("scrollbarStyle","native",function(r){ul(r),Xr(r),r.display.scrollbars.setScrollTop(r.doc.scrollTop),r.display.scrollbars.setScrollLeft(r.doc.scrollLeft)},!0),n("lineNumbers",!1,function(r,i){r.display.gutterSpecs=Yi(r.options.gutters,i),wn(r)},!0),n("firstLineNumber",1,wn,!0),n("lineNumberFormatter",function(r){return r},wn,!0),n("showCursorWhenSelecting",!1,vn,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("selectionsMayTouch",!1),n("readOnly",!1,function(r,i){i=="nocursor"&&(Ur(r),r.display.input.blur()),r.display.input.readOnlyChanged(i)}),n("screenReaderLabel",null,function(r,i){i=i===""?null:i,r.display.input.screenReaderLabelChanged(i)}),n("disableInput",!1,function(r,i){i||r.display.input.reset()},!0),n("dragDrop",!0,Hu),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,vn,!0),n("singleCursorHeightPerLine",!0,vn,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,Sn,!0),n("addModeClass",!1,Sn,!0),n("pollInterval",100),n("undoDepth",200,function(r,i){return r.doc.history.undoDepth=i}),n("historyEventDelay",1250),n("viewportMargin",10,function(r){return r.refresh()},!0),n("maxHighlightLength",1e4,Sn,!0),n("moveInputWithCursor",!0,function(r,i){i||r.display.input.resetPosition()}),n("tabindex",null,function(r,i){return r.display.input.getField().tabIndex=i||""}),n("autofocus",null),n("direction","ltr",function(r,i){return r.doc.setDirection(i)},!0),n("phrases",null)}function Hu(e,t,n){var r=n&&n!=tn;if(!t!=!r){var i=e.display.dragFunctions,o=t?Se:ht;o(e.display.scroller,"dragstart",i.start),o(e.display.scroller,"dragenter",i.enter),o(e.display.scroller,"dragover",i.over),o(e.display.scroller,"dragleave",i.leave),o(e.display.scroller,"drop",i.drop)}}function _u(e){e.options.lineWrapping?(j(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(V(e.display.wrapper,"CodeMirror-wrap"),Ci(e)),Bi(e),St(e),gn(e),setTimeout(function(){return Xr(e)},100)}function Ge(e,t){var n=this;if(!(this instanceof Ge))return new Ge(e,t);this.options=t=t?Me(t):{},Me(aa,t,!1);var r=t.value;typeof r=="string"?r=new Lt(r,t.mode,null,t.lineSeparator,t.direction):t.mode&&(r.modeOption=t.mode),this.doc=r;var i=new Ge.inputStyles[t.inputStyle](this),o=this.display=new eu(e,r,i,t);o.wrapper.CodeMirror=this,la(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),ul(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new Ce,keySeq:null,specialChars:null},t.autofocus&&!N&&o.input.focus(),k&&I<11&&setTimeout(function(){return n.display.input.reset(!0)},20),qu(this),yu(),Mr(this),this.curOp.forceUpdate=!0,yl(this,r),t.autofocus&&!N||this.hasFocus()?setTimeout(function(){n.hasFocus()&&!n.state.focused&&_i(n)},20):Ur(this);for(var l in di)di.hasOwnProperty(l)&&di[l](this,t[l],tn);dl(this),t.finishInit&&t.finishInit(this);for(var a=0;a400}Se(t.scroller,"touchstart",function(s){if(!Qe(e,s)&&!o(s)&&!lo(e,s)){t.input.ensurePolled(),clearTimeout(n);var u=+new Date;t.activeTouch={start:u,moved:!1,prev:u-r.end<=300?r:null},s.touches.length==1&&(t.activeTouch.left=s.touches[0].pageX,t.activeTouch.top=s.touches[0].pageY)}}),Se(t.scroller,"touchmove",function(){t.activeTouch&&(t.activeTouch.moved=!0)}),Se(t.scroller,"touchend",function(s){var u=t.activeTouch;if(u&&!tr(t,s)&&u.left!=null&&!u.moved&&new Date-u.start<300){var h=e.coordsChar(t.activeTouch,"page"),x;!u.prev||l(u,u.prev)?x=new He(h,h):!u.prev.prev||l(u,u.prev.prev)?x=e.findWordAt(h):x=new He(B(h.line,0),Ae(e.doc,B(h.line+1,0))),e.setSelection(x.anchor,x.head),e.focus(),pt(s)}i()}),Se(t.scroller,"touchcancel",i),Se(t.scroller,"scroll",function(){t.scroller.clientHeight&&(xn(e,t.scroller.scrollTop),Cr(e,t.scroller.scrollLeft,!0),Ye(e,"scroll",e))}),Se(t.scroller,"mousewheel",function(s){return gl(e,s)}),Se(t.scroller,"DOMMouseScroll",function(s){return gl(e,s)}),Se(t.wrapper,"scroll",function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0}),t.dragFunctions={enter:function(s){Qe(e,s)||ar(s)},over:function(s){Qe(e,s)||(xu(e,s),ar(s))},start:function(s){return mu(e,s)},drop:lt(e,vu),leave:function(s){Qe(e,s)||jl(e)}};var a=t.input.getField();Se(a,"keyup",function(s){return ea.call(e,s)}),Se(a,"keydown",lt(e,Vl)),Se(a,"keypress",lt(e,ta)),Se(a,"focus",function(s){return _i(e,s)}),Se(a,"blur",function(s){return Ur(e,s)})}var ao=[];Ge.defineInitHook=function(e){return ao.push(e)};function zn(e,t,n,r){var i=e.doc,o;n==null&&(n="add"),n=="smart"&&(i.mode.indent?o=fn(e,t).state:n="prev");var l=e.options.tabSize,a=ye(i,t),s=Fe(a.text,null,l);a.stateAfter&&(a.stateAfter=null);var u=a.text.match(/^\s*/)[0],h;if(!r&&!/\S/.test(a.text))h=0,n="not";else if(n=="smart"&&(h=i.mode.indent(o,a.text.slice(u.length),a.text),h==qe||h>150)){if(!r)return;n="prev"}n=="prev"?t>i.first?h=Fe(ye(i,t-1).text,null,l):h=0:n=="add"?h=s+e.options.indentUnit:n=="subtract"?h=s-e.options.indentUnit:typeof n=="number"&&(h=s+n),h=Math.max(0,h);var x="",D=0;if(e.options.indentWithTabs)for(var L=Math.floor(h/l);L;--L)D+=l,x+=" ";if(Dl,s=zt(t),u=null;if(a&&r.ranges.length>1)if(Ut&&Ut.text.join(` -`)==t){if(r.ranges.length%Ut.text.length==0){u=[];for(var h=0;h=0;D--){var L=r.ranges[D],H=L.from(),Z=L.to();L.empty()&&(n&&n>0?H=B(H.line,H.ch-n):e.state.overwrite&&!a?Z=B(Z.line,Math.min(ye(o,Z.line).text.length,Z.ch+we(s).length)):a&&Ut&&Ut.lineWise&&Ut.text.join(` -`)==s.join(` -`)&&(H=Z=B(H.line,0)));var ie={from:H,to:Z,text:u?u[D%u.length]:s,origin:i||(a?"paste":e.state.cutIncoming>l?"cut":"+input")};Jr(e.doc,ie),ot(e,"inputRead",e,ie)}t&&!a&&ua(e,t),Gr(e),e.curOp.updateInput<2&&(e.curOp.updateInput=x),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function sa(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),!t.isReadOnly()&&!t.options.disableInput&&t.hasFocus()&&At(t,function(){return so(t,n,0,null,"paste")}),!0}function ua(e,t){if(!(!e.options.electricChars||!e.options.smartIndent))for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),l=!1;if(o.electricChars){for(var a=0;a-1){l=zn(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(ye(e.doc,i.head.line).text.slice(0,i.head.ch))&&(l=zn(e,i.head.line,"smart"));l&&ot(e,"electricInput",e,i.head.line)}}}function fa(e){for(var t=[],n=[],r=0;ro&&(zn(this,a.head.line,r,!0),o=a.head.line,l==this.doc.sel.primIndex&&Gr(this));else{var s=a.from(),u=a.to(),h=Math.max(o,s.line);o=Math.min(this.lastLine(),u.line-(u.ch?0:1))+1;for(var x=h;x0&&eo(this.doc,l,new He(s,D[l].to()),$e)}}}),getTokenAt:function(r,i){return ko(this,r,i)},getLineTokens:function(r,i){return ko(this,B(r),i,!0)},getTokenTypeAt:function(r){r=Ae(this.doc,r);var i=xo(this,ye(this.doc,r.line)),o=0,l=(i.length-1)/2,a=r.ch,s;if(a==0)s=i[2];else for(;;){var u=o+l>>1;if((u?i[u*2-1]:0)>=a)l=u;else if(i[u*2+1]s&&(r=s,l=!0),a=ye(this.doc,r)}else a=r;return Yn(this,a,{top:0,left:0},i||"page",o||l).top+(l?this.doc.height-er(a):0)},defaultTextHeight:function(){return jr(this.display)},defaultCharWidth:function(){return Kr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(r,i,o,l,a){var s=this.display;r=jt(this,Ae(this.doc,r));var u=r.bottom,h=r.left;if(i.style.position="absolute",i.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(i),s.sizer.appendChild(i),l=="over")u=r.top;else if(l=="above"||l=="near"){var x=Math.max(s.wrapper.clientHeight,this.doc.height),D=Math.max(s.sizer.clientWidth,s.lineSpace.clientWidth);(l=="above"||r.bottom+i.offsetHeight>x)&&r.top>i.offsetHeight?u=r.top-i.offsetHeight:r.bottom+i.offsetHeight<=x&&(u=r.bottom),h+i.offsetWidth>D&&(h=D-i.offsetWidth)}i.style.top=u+"px",i.style.left=i.style.right="",a=="right"?(h=s.sizer.clientWidth-i.offsetWidth,i.style.right="0px"):(a=="left"?h=0:a=="middle"&&(h=(s.sizer.clientWidth-i.offsetWidth)/2),i.style.left=h+"px"),o&&Hs(this,{left:h,top:u,right:h+i.offsetWidth,bottom:u+i.offsetHeight})},triggerOnKeyDown:yt(Vl),triggerOnKeyPress:yt(ta),triggerOnKeyUp:ea,triggerOnMouseDown:yt(ra),execCommand:function(r){if(En.hasOwnProperty(r))return En[r].call(null,this)},triggerElectric:yt(function(r){ua(this,r)}),findPosH:function(r,i,o,l){var a=1;i<0&&(a=-1,i=-i);for(var s=Ae(this.doc,r),u=0;u0&&h(o.charAt(l-1));)--l;for(;a.5||this.options.lineWrapping)&&Bi(this),Ye(this,"refresh",this)}),swapDoc:yt(function(r){var i=this.doc;return i.cm=null,this.state.selectingText&&this.state.selectingText(),yl(this,r),gn(this),this.display.input.reset(),mn(this,r.scrollLeft,r.scrollTop),this.curOp.forceScroll=!0,ot(this,"swapDoc",this,i),i}),phrase:function(r){var i=this.options.phrases;return i&&Object.prototype.hasOwnProperty.call(i,r)?i[r]:r},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Bt(e),e.registerHelper=function(r,i,o){n.hasOwnProperty(r)||(n[r]=e[r]={_global:[]}),n[r][i]=o},e.registerGlobalHelper=function(r,i,o,l){e.registerHelper(r,i,l),n[r]._global.push({pred:o,val:l})}}function fo(e,t,n,r,i){var o=t,l=n,a=ye(e,t.line),s=i&&e.direction=="rtl"?-n:n;function u(){var he=t.line+s;return he=e.first+e.size?!1:(t=new B(he,t.ch,t.sticky),a=ye(e,he))}function h(he){var se;if(r=="codepoint"){var ge=a.text.charCodeAt(t.ch+(n>0?0:-1));if(isNaN(ge))se=null;else{var Le=n>0?ge>=55296&&ge<56320:ge>=56320&&ge<57343;se=new B(t.line,Math.max(0,Math.min(a.text.length,t.ch+n*(Le?2:1))),-n)}}else i?se=Lu(e.cm,a,t,n):se=ro(a,t,n);if(se==null)if(!he&&u())t=no(i,e.cm,a,t.line,s);else return!1;else t=se;return!0}if(r=="char"||r=="codepoint")h();else if(r=="column")h(!0);else if(r=="word"||r=="group")for(var x=null,D=r=="group",L=e.cm&&e.cm.getHelper(t,"wordChars"),H=!0;!(n<0&&!h(!H));H=!1){var Z=a.text.charAt(t.ch)||` -`,ie=De(Z,L)?"w":D&&Z==` -`?"n":!D||/\s/.test(Z)?null:"p";if(D&&!H&&!ie&&(ie="s"),x&&x!=ie){n<0&&(n=1,h(),t.sticky="after");break}if(ie&&(x=ie),n>0&&!h(!H))break}var ae=ai(e,t,o,l,!0);return We(o,ae)&&(ae.hitSide=!0),ae}function da(e,t,n,r){var i=e.doc,o=t.left,l;if(r=="page"){var a=Math.min(e.display.wrapper.clientHeight,le(e).innerHeight||i(e).documentElement.clientHeight),s=Math.max(a-.5*jr(e.display),3);l=(n>0?t.bottom:t.top)+n*s}else r=="line"&&(l=n>0?t.bottom+3:t.top-3);for(var u;u=Oi(e,o,l),!!u.outside;){if(n<0?l<=0:l>=i.height){u.hitSide=!0;break}l+=n*5}return u}var je=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new Ce,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};je.prototype.init=function(e){var t=this,n=this,r=n.cm,i=n.div=e.lineDiv;i.contentEditable=!0,uo(i,r.options.spellcheck,r.options.autocorrect,r.options.autocapitalize);function o(a){for(var s=a.target;s;s=s.parentNode){if(s==i)return!0;if(/\bCodeMirror-(?:line)?widget\b/.test(s.className))break}return!1}Se(i,"paste",function(a){!o(a)||Qe(r,a)||sa(a,r)||I<=11&&setTimeout(lt(r,function(){return t.updateFromDOM()}),20)}),Se(i,"compositionstart",function(a){t.composing={data:a.data,done:!1}}),Se(i,"compositionupdate",function(a){t.composing||(t.composing={data:a.data,done:!1})}),Se(i,"compositionend",function(a){t.composing&&(a.data!=t.composing.data&&t.readFromDOMSoon(),t.composing.done=!0)}),Se(i,"touchstart",function(){return n.forceCompositionEnd()}),Se(i,"input",function(){t.composing||t.readFromDOMSoon()});function l(a){if(!(!o(a)||Qe(r,a))){if(r.somethingSelected())hi({lineWise:!1,text:r.getSelections()}),a.type=="cut"&&r.replaceSelection("",null,"cut");else if(r.options.lineWiseCopyCut){var s=fa(r);hi({lineWise:!0,text:s.text}),a.type=="cut"&&r.operation(function(){r.setSelections(s.ranges,0,$e),r.replaceSelection("",null,"cut")})}else return;if(a.clipboardData){a.clipboardData.clearData();var u=Ut.text.join(` -`);if(a.clipboardData.setData("Text",u),a.clipboardData.getData("Text")==u){a.preventDefault();return}}var h=ca(),x=h.firstChild;uo(x),r.display.lineSpace.insertBefore(h,r.display.lineSpace.firstChild),x.value=Ut.text.join(` -`);var D=y(Te(i));v(x),setTimeout(function(){r.display.lineSpace.removeChild(h),D.focus(),D==i&&n.showPrimarySelection()},50)}}Se(i,"copy",l),Se(i,"cut",l)},je.prototype.screenReaderLabelChanged=function(e){e?this.div.setAttribute("aria-label",e):this.div.removeAttribute("aria-label")},je.prototype.prepareSelection=function(){var e=rl(this.cm,!1);return e.focus=y(Te(this.div))==this.div,e},je.prototype.showSelection=function(e,t){!e||!this.cm.display.view.length||((e.focus||t)&&this.showPrimarySelection(),this.showMultipleSelections(e))},je.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},je.prototype.showPrimarySelection=function(){var e=this.getSelection(),t=this.cm,n=t.doc.sel.primary(),r=n.from(),i=n.to();if(t.display.viewTo==t.display.viewFrom||r.line>=t.display.viewTo||i.line=t.display.viewFrom&&ha(t,r)||{node:a[0].measure.map[2],offset:0},u=i.linee.firstLine()&&(r=B(r.line-1,ye(e.doc,r.line-1).length)),i.ch==ye(e.doc,i.line).text.length&&i.linet.viewTo-1)return!1;var o,l,a;r.line==t.viewFrom||(o=Tr(e,r.line))==0?(l=f(t.view[0].line),a=t.view[0].node):(l=f(t.view[o].line),a=t.view[o-1].node.nextSibling);var s=Tr(e,i.line),u,h;if(s==t.view.length-1?(u=t.viewTo-1,h=t.lineDiv.lastChild):(u=f(t.view[s+1].line)-1,h=t.view[s+1].node.previousSibling),!a)return!1;for(var x=e.doc.splitLines(Uu(e,a,h,l,u)),D=$t(e.doc,B(l,0),B(u,ye(e.doc,u).text.length));x.length>1&&D.length>1;)if(we(x)==we(D))x.pop(),D.pop(),u--;else if(x[0]==D[0])x.shift(),D.shift(),l++;else break;for(var L=0,H=0,Z=x[0],ie=D[0],ae=Math.min(Z.length,ie.length);Lr.ch&&he.charCodeAt(he.length-H-1)==se.charCodeAt(se.length-H-1);)L--,H++;x[x.length-1]=he.slice(0,he.length-H).replace(/^\u200b+/,""),x[0]=x[0].slice(L).replace(/\u200b+$/,"");var Le=B(l,L),ke=B(u,D.length?we(D).length-H:0);if(x.length>1||x[0]||ce(Le,ke))return Zr(e.doc,x,Le,ke,"+input"),!0},je.prototype.ensurePolled=function(){this.forceCompositionEnd()},je.prototype.reset=function(){this.forceCompositionEnd()},je.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},je.prototype.readFromDOMSoon=function(){var e=this;this.readDOMTimeout==null&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing)if(e.composing.done)e.composing=null;else return;e.updateFromDOM()},80))},je.prototype.updateFromDOM=function(){var e=this;(this.cm.isReadOnly()||!this.pollContent())&&At(this.cm,function(){return St(e.cm)})},je.prototype.setUneditable=function(e){e.contentEditable="false"},je.prototype.onKeyPress=function(e){e.charCode==0||this.composing||(e.preventDefault(),this.cm.isReadOnly()||lt(this.cm,so)(this.cm,String.fromCharCode(e.charCode==null?e.keyCode:e.charCode),0))},je.prototype.readOnlyChanged=function(e){this.div.contentEditable=String(e!="nocursor")},je.prototype.onContextMenu=function(){},je.prototype.resetPosition=function(){},je.prototype.needsContentAttribute=!0;function ha(e,t){var n=Ai(e,t.line);if(!n||n.hidden)return null;var r=ye(e.doc,t.line),i=qo(n,r,t.line),o=Re(r,e.doc.direction),l="left";if(o){var a=lr(o,t.ch);l=a%2?"right":"left"}var s=Uo(i.map,t.ch,l);return s.offset=s.collapse=="right"?s.end:s.start,s}function Ku(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function rn(e,t){return t&&(e.bad=!0),e}function Uu(e,t,n,r,i){var o="",l=!1,a=e.doc.lineSeparator(),s=!1;function u(L){return function(H){return H.id==L}}function h(){l&&(o+=a,s&&(o+=a),l=s=!1)}function x(L){L&&(h(),o+=L)}function D(L){if(L.nodeType==1){var H=L.getAttribute("cm-text");if(H){x(H);return}var Z=L.getAttribute("cm-marker"),ie;if(Z){var ae=e.findMarks(B(r,0),B(i+1,0),u(+Z));ae.length&&(ie=ae[0].find(0))&&x($t(e.doc,ie.from,ie.to).join(a));return}if(L.getAttribute("contenteditable")=="false")return;var he=/^(pre|div|p|li|table|br)$/i.test(L.nodeName);if(!/^br$/i.test(L.nodeName)&&L.textContent.length==0)return;he&&h();for(var se=0;se=9&&t.hasSelection&&(t.hasSelection=null),n.poll()}),Se(i,"paste",function(l){Qe(r,l)||sa(l,r)||(r.state.pasteIncoming=+new Date,n.fastPoll())});function o(l){if(!Qe(r,l)){if(r.somethingSelected())hi({lineWise:!1,text:r.getSelections()});else if(r.options.lineWiseCopyCut){var a=fa(r);hi({lineWise:!0,text:a.text}),l.type=="cut"?r.setSelections(a.ranges,null,$e):(n.prevInput="",i.value=a.text.join(` -`),v(i))}else return;l.type=="cut"&&(r.state.cutIncoming=+new Date)}}Se(i,"cut",o),Se(i,"copy",o),Se(e.scroller,"paste",function(l){if(!(tr(e,l)||Qe(r,l))){if(!i.dispatchEvent){r.state.pasteIncoming=+new Date,n.focus();return}var a=new Event("paste");a.clipboardData=l.clipboardData,i.dispatchEvent(a)}}),Se(e.lineSpace,"selectstart",function(l){tr(e,l)||pt(l)}),Se(i,"compositionstart",function(){var l=r.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:l,range:r.markText(l,r.getCursor("to"),{className:"CodeMirror-composing"})}}),Se(i,"compositionend",function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)})},Ve.prototype.createField=function(e){this.wrapper=ca(),this.textarea=this.wrapper.firstChild;var t=this.cm.options;uo(this.textarea,t.spellcheck,t.autocorrect,t.autocapitalize)},Ve.prototype.screenReaderLabelChanged=function(e){e?this.textarea.setAttribute("aria-label",e):this.textarea.removeAttribute("aria-label")},Ve.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=rl(e);if(e.options.moveInputWithCursor){var i=jt(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),l=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+l.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+l.left-o.left))}return r},Ve.prototype.showSelection=function(e){var t=this.cm,n=t.display;G(n.cursorDiv,e.cursors),G(n.selectionDiv,e.selection),e.teTop!=null&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Ve.prototype.reset=function(e){if(!(this.contextMenuPending||this.composing&&e)){var t=this.cm;if(this.resetting=!0,t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&v(this.textarea),k&&I>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",k&&I>=9&&(this.hasSelection=null));this.resetting=!1}},Ve.prototype.getField=function(){return this.textarea},Ve.prototype.supportsTouch=function(){return!1},Ve.prototype.focus=function(){if(this.cm.options.readOnly!="nocursor"&&(!N||y(Te(this.textarea))!=this.textarea))try{this.textarea.focus()}catch{}},Ve.prototype.blur=function(){this.textarea.blur()},Ve.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Ve.prototype.receivedFocus=function(){this.slowPoll()},Ve.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},Ve.prototype.fastPoll=function(){var e=!1,t=this;t.pollingFast=!0;function n(){var r=t.poll();!r&&!e?(e=!0,t.polling.set(60,n)):(t.pollingFast=!1,t.slowPoll())}t.polling.set(20,n)},Ve.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||this.resetting||!t.state.focused||ur(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(k&&I>=9&&this.hasSelection===i||z&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(o==8203&&!r&&(r="​"),o==8666)return this.reset(),this.cm.execCommand("undo")}for(var l=0,a=Math.min(r.length,i.length);l1e3||i.indexOf(` -`)>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Ve.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Ve.prototype.onKeyPress=function(){k&&I>=9&&(this.hasSelection=null),this.fastPoll()},Ve.prototype.onContextMenu=function(e){var t=this,n=t.cm,r=n.display,i=t.textarea;t.contextMenuPending&&t.contextMenuPending();var o=Lr(n,e),l=r.scroller.scrollTop;if(!o||A)return;var a=n.options.resetSelectionOnContextMenu;a&&n.doc.sel.contains(o)==-1&<(n,gt)(n.doc,pr(o),$e);var s=i.style.cssText,u=t.wrapper.style.cssText,h=t.wrapper.offsetParent.getBoundingClientRect();t.wrapper.style.cssText="position: static",i.style.cssText=`position: absolute; width: 30px; height: 30px; - top: `+(e.clientY-h.top-5)+"px; left: "+(e.clientX-h.left-5)+`px; - z-index: 1000; background: `+(k?"rgba(255, 255, 255, .05)":"transparent")+`; - outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);`;var x;Y&&(x=i.ownerDocument.defaultView.scrollY),r.input.focus(),Y&&i.ownerDocument.defaultView.scrollTo(null,x),r.input.reset(),n.somethingSelected()||(i.value=t.prevInput=" "),t.contextMenuPending=L,r.selForContextMenu=n.doc.sel,clearTimeout(r.detectingSelectAll);function D(){if(i.selectionStart!=null){var Z=n.somethingSelected(),ie="​"+(Z?i.value:"");i.value="⇚",i.value=ie,t.prevInput=Z?"":"​",i.selectionStart=1,i.selectionEnd=ie.length,r.selForContextMenu=n.doc.sel}}function L(){if(t.contextMenuPending==L&&(t.contextMenuPending=!1,t.wrapper.style.cssText=u,i.style.cssText=s,k&&I<9&&r.scrollbars.setScrollTop(r.scroller.scrollTop=l),i.selectionStart!=null)){(!k||k&&I<9)&&D();var Z=0,ie=function(){r.selForContextMenu==n.doc.sel&&i.selectionStart==0&&i.selectionEnd>0&&t.prevInput=="​"?lt(n,El)(n):Z++<10?r.detectingSelectAll=setTimeout(ie,500):(r.selForContextMenu=null,r.input.reset())};r.detectingSelectAll=setTimeout(ie,200)}}if(k&&I>=9&&D(),J){ar(e);var H=function(){ht(window,"mouseup",H),setTimeout(L,20)};Se(window,"mouseup",H)}else setTimeout(L,50)},Ve.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled=e=="nocursor",this.textarea.readOnly=!!e},Ve.prototype.setUneditable=function(){},Ve.prototype.needsContentAttribute=!1;function Xu(e,t){if(t=t?Me(t):{},t.value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),t.autofocus==null){var n=y(Te(e));t.autofocus=n==e||e.getAttribute("autofocus")!=null&&n==document.body}function r(){e.value=a.getValue()}var i;if(e.form&&(Se(e.form,"submit",r),!t.leaveSubmitMethodAlone)){var o=e.form;i=o.submit;try{var l=o.submit=function(){r(),o.submit=i,o.submit(),o.submit=l}}catch{}}t.finishInit=function(s){s.save=r,s.getTextArea=function(){return e},s.toTextArea=function(){s.toTextArea=isNaN,r(),e.parentNode.removeChild(s.getWrapperElement()),e.style.display="",e.form&&(ht(e.form,"submit",r),!t.leaveSubmitMethodAlone&&typeof e.form.submit=="function"&&(e.form.submit=i))}},e.style.display="none";var a=Ge(function(s){return e.parentNode.insertBefore(s,e.nextSibling)},t);return a}function Yu(e){e.off=ht,e.on=Se,e.wheelEventPixels=tu,e.Doc=Lt,e.splitLines=zt,e.countColumn=Fe,e.findColumn=_e,e.isWordChar=me,e.Pass=qe,e.signal=Ye,e.Line=Hr,e.changeEnd=gr,e.scrollbarModel=sl,e.Pos=B,e.cmpPos=ce,e.modes=Pr,e.mimeModes=Ht,e.resolveMode=Ir,e.getMode=zr,e.modeExtensions=fr,e.extendMode=Br,e.copyState=Gt,e.startState=Rr,e.innerMode=sn,e.commands=En,e.keyMap=nr,e.keyName=Yl,e.isModifierKey=Gl,e.lookupKey=Vr,e.normalizeKeyMap=Su,e.StringStream=Je,e.SharedTextMarker=Fn,e.TextMarker=mr,e.LineWidget=Mn,e.e_preventDefault=pt,e.e_stopPropagation=Er,e.e_stop=ar,e.addClass=j,e.contains=g,e.rmClass=V,e.keyNames=xr}Wu(Ge),ju(Ge);var Qu="iter insert remove copy getEditor constructor".split(" ");for(var gi in Lt.prototype)Lt.prototype.hasOwnProperty(gi)&&ve(Qu,gi)<0&&(Ge.prototype[gi]=(function(e){return function(){return e.apply(this.doc,arguments)}})(Lt.prototype[gi]));return Bt(Lt),Ge.inputStyles={textarea:Ve,contenteditable:je},Ge.defineMode=function(e){!Ge.defaults.mode&&e!="null"&&(Ge.defaults.mode=e),_t.apply(this,arguments)},Ge.defineMIME=kr,Ge.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Ge.defineMIME("text/plain","null"),Ge.defineExtension=function(e,t){Ge.prototype[e]=t},Ge.defineDocExtension=function(e,t){Lt.prototype[e]=t},Ge.fromTextArea=Xu,Yu(Ge),Ge.version="5.65.18",Ge}))})(vi)),vi.exports}var $u=mt();const df=Ju($u);var ga={exports:{}},va;function Xa(){return va||(va=1,(function(ct,xt){(function(b){b(mt())})(function(b){b.defineMode("css",function(J,P){var V=P.inline;P.propertyKeywords||(P=b.resolveMode("text/css"));var F=J.indentUnit,G=P.tokenHooks,c=P.documentTypes||{},T=P.mediaTypes||{},C=P.mediaFeatures||{},g=P.mediaValueKeywords||{},y=P.propertyKeywords||{},j=P.nonStandardPropertyKeywords||{},de=P.fontProperties||{},v=P.counterDescriptors||{},d=P.colorKeywords||{},fe=P.valueKeywords||{},Te=P.allowNested,le=P.lineComment,xe=P.supportsAtComponent===!0,Me=J.highlightNonStandardPropertyKeywords!==!1,Fe,Ce;function ve(E,ee){return Fe=ee,E}function Oe(E,ee){var K=E.next();if(G[K]){var ze=G[K](E,ee);if(ze!==!1)return ze}if(K=="@")return E.eatWhile(/[\w\\\-]/),ve("def",E.current());if(K=="="||(K=="~"||K=="|")&&E.eat("="))return ve(null,"compare");if(K=='"'||K=="'")return ee.tokenize=qe(K),ee.tokenize(E,ee);if(K=="#")return E.eatWhile(/[\w\\\-]/),ve("atom","hash");if(K=="!")return E.match(/^\s*\w*/),ve("keyword","important");if(/\d/.test(K)||K=="."&&E.eat(/\d/))return E.eatWhile(/[\w.%]/),ve("number","unit");if(K==="-"){if(/[\d.]/.test(E.peek()))return E.eatWhile(/[\w.%]/),ve("number","unit");if(E.match(/^-[\w\\\-]*/))return E.eatWhile(/[\w\\\-]/),E.match(/^\s*:/,!1)?ve("variable-2","variable-definition"):ve("variable-2","variable");if(E.match(/^\w+-/))return ve("meta","meta")}else return/[,+>*\/]/.test(K)?ve(null,"select-op"):K=="."&&E.match(/^-?[_a-z][_a-z0-9-]*/i)?ve("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(K)?ve(null,K):E.match(/^[\w-.]+(?=\()/)?(/^(url(-prefix)?|domain|regexp)$/i.test(E.current())&&(ee.tokenize=$e),ve("variable callee","variable")):/[\w\\\-]/.test(K)?(E.eatWhile(/[\w\\\-]/),ve("property","word")):ve(null,null)}function qe(E){return function(ee,K){for(var ze=!1,me;(me=ee.next())!=null;){if(me==E&&!ze){E==")"&&ee.backUp(1);break}ze=!ze&&me=="\\"}return(me==E||!ze&&E!=")")&&(K.tokenize=null),ve("string","string")}}function $e(E,ee){return E.next(),E.match(/^\s*[\"\')]/,!1)?ee.tokenize=null:ee.tokenize=qe(")"),ve(null,"(")}function dt(E,ee,K){this.type=E,this.indent=ee,this.prev=K}function Pe(E,ee,K,ze){return E.context=new dt(K,ee.indentation()+(ze===!1?0:F),E.context),K}function _e(E){return E.context.prev&&(E.context=E.context.prev),E.context.type}function Ue(E,ee,K){return Ie[K.context.type](E,ee,K)}function et(E,ee,K,ze){for(var me=ze||1;me>0;me--)K.context=K.context.prev;return Ue(E,ee,K)}function we(E){var ee=E.current().toLowerCase();fe.hasOwnProperty(ee)?Ce="atom":d.hasOwnProperty(ee)?Ce="keyword":Ce="variable"}var Ie={};return Ie.top=function(E,ee,K){if(E=="{")return Pe(K,ee,"block");if(E=="}"&&K.context.prev)return _e(K);if(xe&&/@component/i.test(E))return Pe(K,ee,"atComponentBlock");if(/^@(-moz-)?document$/i.test(E))return Pe(K,ee,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/i.test(E))return Pe(K,ee,"atBlock");if(/^@(font-face|counter-style)/i.test(E))return K.stateArg=E,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(E))return"keyframes";if(E&&E.charAt(0)=="@")return Pe(K,ee,"at");if(E=="hash")Ce="builtin";else if(E=="word")Ce="tag";else{if(E=="variable-definition")return"maybeprop";if(E=="interpolation")return Pe(K,ee,"interpolation");if(E==":")return"pseudo";if(Te&&E=="(")return Pe(K,ee,"parens")}return K.context.type},Ie.block=function(E,ee,K){if(E=="word"){var ze=ee.current().toLowerCase();return y.hasOwnProperty(ze)?(Ce="property","maybeprop"):j.hasOwnProperty(ze)?(Ce=Me?"string-2":"property","maybeprop"):Te?(Ce=ee.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(Ce+=" error","maybeprop")}else return E=="meta"?"block":!Te&&(E=="hash"||E=="qualifier")?(Ce="error","block"):Ie.top(E,ee,K)},Ie.maybeprop=function(E,ee,K){return E==":"?Pe(K,ee,"prop"):Ue(E,ee,K)},Ie.prop=function(E,ee,K){if(E==";")return _e(K);if(E=="{"&&Te)return Pe(K,ee,"propBlock");if(E=="}"||E=="{")return et(E,ee,K);if(E=="(")return Pe(K,ee,"parens");if(E=="hash"&&!/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(ee.current()))Ce+=" error";else if(E=="word")we(ee);else if(E=="interpolation")return Pe(K,ee,"interpolation");return"prop"},Ie.propBlock=function(E,ee,K){return E=="}"?_e(K):E=="word"?(Ce="property","maybeprop"):K.context.type},Ie.parens=function(E,ee,K){return E=="{"||E=="}"?et(E,ee,K):E==")"?_e(K):E=="("?Pe(K,ee,"parens"):E=="interpolation"?Pe(K,ee,"interpolation"):(E=="word"&&we(ee),"parens")},Ie.pseudo=function(E,ee,K){return E=="meta"?"pseudo":E=="word"?(Ce="variable-3",K.context.type):Ue(E,ee,K)},Ie.documentTypes=function(E,ee,K){return E=="word"&&c.hasOwnProperty(ee.current())?(Ce="tag",K.context.type):Ie.atBlock(E,ee,K)},Ie.atBlock=function(E,ee,K){if(E=="(")return Pe(K,ee,"atBlock_parens");if(E=="}"||E==";")return et(E,ee,K);if(E=="{")return _e(K)&&Pe(K,ee,Te?"block":"top");if(E=="interpolation")return Pe(K,ee,"interpolation");if(E=="word"){var ze=ee.current().toLowerCase();ze=="only"||ze=="not"||ze=="and"||ze=="or"?Ce="keyword":T.hasOwnProperty(ze)?Ce="attribute":C.hasOwnProperty(ze)?Ce="property":g.hasOwnProperty(ze)?Ce="keyword":y.hasOwnProperty(ze)?Ce="property":j.hasOwnProperty(ze)?Ce=Me?"string-2":"property":fe.hasOwnProperty(ze)?Ce="atom":d.hasOwnProperty(ze)?Ce="keyword":Ce="error"}return K.context.type},Ie.atComponentBlock=function(E,ee,K){return E=="}"?et(E,ee,K):E=="{"?_e(K)&&Pe(K,ee,Te?"block":"top",!1):(E=="word"&&(Ce="error"),K.context.type)},Ie.atBlock_parens=function(E,ee,K){return E==")"?_e(K):E=="{"||E=="}"?et(E,ee,K,2):Ie.atBlock(E,ee,K)},Ie.restricted_atBlock_before=function(E,ee,K){return E=="{"?Pe(K,ee,"restricted_atBlock"):E=="word"&&K.stateArg=="@counter-style"?(Ce="variable","restricted_atBlock_before"):Ue(E,ee,K)},Ie.restricted_atBlock=function(E,ee,K){return E=="}"?(K.stateArg=null,_e(K)):E=="word"?(K.stateArg=="@font-face"&&!de.hasOwnProperty(ee.current().toLowerCase())||K.stateArg=="@counter-style"&&!v.hasOwnProperty(ee.current().toLowerCase())?Ce="error":Ce="property","maybeprop"):"restricted_atBlock"},Ie.keyframes=function(E,ee,K){return E=="word"?(Ce="variable","keyframes"):E=="{"?Pe(K,ee,"top"):Ue(E,ee,K)},Ie.at=function(E,ee,K){return E==";"?_e(K):E=="{"||E=="}"?et(E,ee,K):(E=="word"?Ce="tag":E=="hash"&&(Ce="builtin"),"at")},Ie.interpolation=function(E,ee,K){return E=="}"?_e(K):E=="{"||E==";"?et(E,ee,K):(E=="word"?Ce="variable":E!="variable"&&E!="("&&E!=")"&&(Ce="error"),"interpolation")},{startState:function(E){return{tokenize:null,state:V?"block":"top",stateArg:null,context:new dt(V?"block":"top",E||0,null)}},token:function(E,ee){if(!ee.tokenize&&E.eatSpace())return null;var K=(ee.tokenize||Oe)(E,ee);return K&&typeof K=="object"&&(Fe=K[1],K=K[0]),Ce=K,Fe!="comment"&&(ee.state=Ie[ee.state](Fe,E,ee)),Ce},indent:function(E,ee){var K=E.context,ze=ee&&ee.charAt(0),me=K.indent;return K.type=="prop"&&(ze=="}"||ze==")")&&(K=K.prev),K.prev&&(ze=="}"&&(K.type=="block"||K.type=="top"||K.type=="interpolation"||K.type=="restricted_atBlock")?(K=K.prev,me=K.indent):(ze==")"&&(K.type=="parens"||K.type=="atBlock_parens")||ze=="{"&&(K.type=="at"||K.type=="atBlock"))&&(me=Math.max(0,K.indent-F))),me},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:le,fold:"brace"}});function pe(J){for(var P={},V=0;V")):null:c.match("--")?C(ue("comment","-->")):c.match("DOCTYPE",!0,!0)?(c.eatWhile(/[\w\._\-]/),C(O(1))):null:c.eat("?")?(c.eatWhile(/[\w\._\-]/),T.tokenize=ue("meta","?>"),"meta"):(ne=c.eat("/")?"closeTag":"openTag",T.tokenize=A,"tag bracket");if(g=="&"){var y;return c.eat("#")?c.eat("x")?y=c.eatWhile(/[a-fA-F\d]/)&&c.eat(";"):y=c.eatWhile(/[\d]/)&&c.eat(";"):y=c.eatWhile(/[\w\.\-:]/)&&c.eat(";"),y?"atom":"error"}else return c.eatWhile(/[^&<]/),null}R.isInText=!0;function A(c,T){var C=c.next();if(C==">"||C=="/"&&c.eat(">"))return T.tokenize=R,ne=C==">"?"endTag":"selfcloseTag","tag bracket";if(C=="=")return ne="equals",null;if(C=="<"){T.tokenize=R,T.state=X,T.tagName=T.tagStart=null;var g=T.tokenize(c,T);return g?g+" tag error":"tag error"}else return/[\'\"]/.test(C)?(T.tokenize=$(C),T.stringStartCol=c.column(),T.tokenize(c,T)):(c.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function $(c){var T=function(C,g){for(;!C.eol();)if(C.next()==c){g.tokenize=A;break}return"string"};return T.isInAttribute=!0,T}function ue(c,T){return function(C,g){for(;!C.eol();){if(C.match(T)){g.tokenize=R;break}C.next()}return c}}function O(c){return function(T,C){for(var g;(g=T.next())!=null;){if(g=="<")return C.tokenize=O(c+1),C.tokenize(T,C);if(g==">")if(c==1){C.tokenize=R;break}else return C.tokenize=O(c-1),C.tokenize(T,C)}return"meta"}}function w(c){return c&&c.toLowerCase()}function M(c,T,C){this.prev=c.context,this.tagName=T||"",this.indent=c.indented,this.startOfLine=C,(k.doNotIndent.hasOwnProperty(T)||c.context&&c.context.noIndent)&&(this.noIndent=!0)}function N(c){c.context&&(c.context=c.context.prev)}function z(c,T){for(var C;;){if(!c.context||(C=c.context.tagName,!k.contextGrabbers.hasOwnProperty(w(C))||!k.contextGrabbers[w(C)].hasOwnProperty(w(T))))return;N(c)}}function X(c,T,C){return c=="openTag"?(C.tagStart=T.column(),q):c=="closeTag"?p:X}function q(c,T,C){return c=="word"?(C.tagName=T.current(),S="tag",P):k.allowMissingTagName&&c=="endTag"?(S="tag bracket",P(c,T,C)):(S="error",q)}function p(c,T,C){if(c=="word"){var g=T.current();return C.context&&C.context.tagName!=g&&k.implicitlyClosed.hasOwnProperty(w(C.context.tagName))&&N(C),C.context&&C.context.tagName==g||k.matchClosing===!1?(S="tag",W):(S="tag error",J)}else return k.allowMissingTagName&&c=="endTag"?(S="tag bracket",W(c,T,C)):(S="error",J)}function W(c,T,C){return c!="endTag"?(S="error",W):(N(C),X)}function J(c,T,C){return S="error",W(c,T,C)}function P(c,T,C){if(c=="word")return S="attribute",V;if(c=="endTag"||c=="selfcloseTag"){var g=C.tagName,y=C.tagStart;return C.tagName=C.tagStart=null,c=="selfcloseTag"||k.autoSelfClosers.hasOwnProperty(w(g))?z(C,g):(z(C,g),C.context=new M(C,g,y==C.indented)),X}return S="error",P}function V(c,T,C){return c=="equals"?F:(k.allowMissing||(S="error"),P(c,T,C))}function F(c,T,C){return c=="string"?G:c=="word"&&k.allowUnquoted?(S="string",P):(S="error",P(c,T,C))}function G(c,T,C){return c=="string"?G:P(c,T,C)}return{startState:function(c){var T={tokenize:R,state:X,indented:c||0,tagName:null,tagStart:null,context:null};return c!=null&&(T.baseIndent=c),T},token:function(c,T){if(!T.tagName&&c.sol()&&(T.indented=c.indentation()),c.eatSpace())return null;ne=null;var C=T.tokenize(c,T);return(C||ne)&&C!="comment"&&(S=null,T.state=T.state(ne||C,c,T),S&&(C=S=="error"?C+" error":S)),C},indent:function(c,T,C){var g=c.context;if(c.tokenize.isInAttribute)return c.tagStart==c.indented?c.stringStartCol+1:c.indented+Q;if(g&&g.noIndent)return b.Pass;if(c.tokenize!=A&&c.tokenize!=R)return C?C.match(/^(\s*)/)[0].length:0;if(c.tagName)return k.multilineTagIndentPastTag!==!1?c.tagStart+c.tagName.length+2:c.tagStart+Q*(k.multilineTagIndentFactor||1);if(k.alignCDATA&&/$/,blockCommentStart:"",configuration:k.htmlMode?"html":"xml",helperType:k.htmlMode?"html":"xml",skipAttribute:function(c){c.state==F&&(c.state=P)},xmlCurrentTag:function(c){return c.tagName?{name:c.tagName,close:c.type=="closeTag"}:null},xmlCurrentContext:function(c){for(var T=[],C=c.context;C;C=C.prev)T.push(C.tagName);return T.reverse()}}}),b.defineMIME("text/xml","xml"),b.defineMIME("application/xml","xml"),b.mimeModes.hasOwnProperty("text/html")||b.defineMIME("text/html",{name:"xml",htmlMode:!0})})})()),xa.exports}var ba={exports:{}},ka;function Qa(){return ka||(ka=1,(function(ct,xt){(function(b){b(mt())})(function(b){b.defineMode("javascript",function(pe,_){var te=pe.indentUnit,oe=_.statementIndent,Q=_.jsonld,k=_.json||Q,I=_.trackScope!==!1,Y=_.typescript,ne=_.wordCharacters||/[\w$\xa1-\uffff]/,S=(function(){function f(it){return{type:it,style:"keyword"}}var m=f("keyword a"),U=f("keyword b"),re=f("keyword c"),B=f("keyword d"),ce=f("operator"),We={type:"atom",style:"atom"};return{if:f("if"),while:m,with:m,else:U,do:U,try:U,finally:U,return:B,break:B,continue:B,new:f("new"),delete:re,void:re,throw:re,debugger:f("debugger"),var:f("var"),const:f("var"),let:f("var"),function:f("function"),catch:f("catch"),for:f("for"),switch:f("switch"),case:f("case"),default:f("default"),in:ce,typeof:ce,instanceof:ce,true:We,false:We,null:We,undefined:We,NaN:We,Infinity:We,this:f("this"),class:f("class"),super:f("atom"),yield:re,export:f("export"),import:f("import"),extends:re,await:re}})(),R=/[+\-*&%=<>!?|~^@]/,A=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function $(f){for(var m=!1,U,re=!1;(U=f.next())!=null;){if(!m){if(U=="/"&&!re)return;U=="["?re=!0:re&&U=="]"&&(re=!1)}m=!m&&U=="\\"}}var ue,O;function w(f,m,U){return ue=f,O=U,m}function M(f,m){var U=f.next();if(U=='"'||U=="'")return m.tokenize=N(U),m.tokenize(f,m);if(U=="."&&f.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return w("number","number");if(U=="."&&f.match(".."))return w("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(U))return w(U);if(U=="="&&f.eat(">"))return w("=>","operator");if(U=="0"&&f.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return w("number","number");if(/\d/.test(U))return f.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),w("number","number");if(U=="/")return f.eat("*")?(m.tokenize=z,z(f,m)):f.eat("/")?(f.skipToEnd(),w("comment","comment")):Et(f,m,1)?($(f),f.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),w("regexp","string-2")):(f.eat("="),w("operator","operator",f.current()));if(U=="`")return m.tokenize=X,X(f,m);if(U=="#"&&f.peek()=="!")return f.skipToEnd(),w("meta","meta");if(U=="#"&&f.eatWhile(ne))return w("variable","property");if(U=="<"&&f.match("!--")||U=="-"&&f.match("->")&&!/\S/.test(f.string.slice(0,f.start)))return f.skipToEnd(),w("comment","comment");if(R.test(U))return(U!=">"||!m.lexical||m.lexical.type!=">")&&(f.eat("=")?(U=="!"||U=="=")&&f.eat("="):/[<>*+\-|&?]/.test(U)&&(f.eat(U),U==">"&&f.eat(U))),U=="?"&&f.eat(".")?w("."):w("operator","operator",f.current());if(ne.test(U)){f.eatWhile(ne);var re=f.current();if(m.lastType!="."){if(S.propertyIsEnumerable(re)){var B=S[re];return w(B.type,B.style,re)}if(re=="async"&&f.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return w("async","keyword",re)}return w("variable","variable",re)}}function N(f){return function(m,U){var re=!1,B;if(Q&&m.peek()=="@"&&m.match(A))return U.tokenize=M,w("jsonld-keyword","meta");for(;(B=m.next())!=null&&!(B==f&&!re);)re=!re&&B=="\\";return re||(U.tokenize=M),w("string","string")}}function z(f,m){for(var U=!1,re;re=f.next();){if(re=="/"&&U){m.tokenize=M;break}U=re=="*"}return w("comment","comment")}function X(f,m){for(var U=!1,re;(re=f.next())!=null;){if(!U&&(re=="`"||re=="$"&&f.eat("{"))){m.tokenize=M;break}U=!U&&re=="\\"}return w("quasi","string-2",f.current())}var q="([{}])";function p(f,m){m.fatArrowAt&&(m.fatArrowAt=null);var U=f.string.indexOf("=>",f.start);if(!(U<0)){if(Y){var re=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(f.string.slice(f.start,U));re&&(U=re.index)}for(var B=0,ce=!1,We=U-1;We>=0;--We){var it=f.string.charAt(We),wt=q.indexOf(it);if(wt>=0&&wt<3){if(!B){++We;break}if(--B==0){it=="("&&(ce=!0);break}}else if(wt>=3&&wt<6)++B;else if(ne.test(it))ce=!0;else if(/["'\/`]/.test(it))for(;;--We){if(We==0)return;var Wr=f.string.charAt(We-1);if(Wr==it&&f.string.charAt(We-2)!="\\"){We--;break}}else if(ce&&!B){++We;break}}ce&&!B&&(m.fatArrowAt=We)}}var W={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function J(f,m,U,re,B,ce){this.indented=f,this.column=m,this.type=U,this.prev=B,this.info=ce,re!=null&&(this.align=re)}function P(f,m){if(!I)return!1;for(var U=f.localVars;U;U=U.next)if(U.name==m)return!0;for(var re=f.context;re;re=re.prev)for(var U=re.vars;U;U=U.next)if(U.name==m)return!0}function V(f,m,U,re,B){var ce=f.cc;for(F.state=f,F.stream=B,F.marked=null,F.cc=ce,F.style=m,f.lexical.hasOwnProperty("align")||(f.lexical.align=!0);;){var We=ce.length?ce.pop():k?ve:Fe;if(We(U,re)){for(;ce.length&&ce[ce.length-1].lex;)ce.pop()();return F.marked?F.marked:U=="variable"&&P(f,re)?"variable-2":m}}}var F={state:null,marked:null,cc:null};function G(){for(var f=arguments.length-1;f>=0;f--)F.cc.push(arguments[f])}function c(){return G.apply(null,arguments),!0}function T(f,m){for(var U=m;U;U=U.next)if(U.name==f)return!0;return!1}function C(f){var m=F.state;if(F.marked="def",!!I){if(m.context){if(m.lexical.info=="var"&&m.context&&m.context.block){var U=g(f,m.context);if(U!=null){m.context=U;return}}else if(!T(f,m.localVars)){m.localVars=new de(f,m.localVars);return}}_.globalVars&&!T(f,m.globalVars)&&(m.globalVars=new de(f,m.globalVars))}}function g(f,m){if(m)if(m.block){var U=g(f,m.prev);return U?U==m.prev?m:new j(U,m.vars,!0):null}else return T(f,m.vars)?m:new j(m.prev,new de(f,m.vars),!1);else return null}function y(f){return f=="public"||f=="private"||f=="protected"||f=="abstract"||f=="readonly"}function j(f,m,U){this.prev=f,this.vars=m,this.block=U}function de(f,m){this.name=f,this.next=m}var v=new de("this",new de("arguments",null));function d(){F.state.context=new j(F.state.context,F.state.localVars,!1),F.state.localVars=v}function fe(){F.state.context=new j(F.state.context,F.state.localVars,!0),F.state.localVars=null}d.lex=fe.lex=!0;function Te(){F.state.localVars=F.state.context.vars,F.state.context=F.state.context.prev}Te.lex=!0;function le(f,m){var U=function(){var re=F.state,B=re.indented;if(re.lexical.type=="stat")B=re.lexical.indented;else for(var ce=re.lexical;ce&&ce.type==")"&&ce.align;ce=ce.prev)B=ce.indented;re.lexical=new J(B,F.stream.column(),f,null,re.lexical,m)};return U.lex=!0,U}function xe(){var f=F.state;f.lexical.prev&&(f.lexical.type==")"&&(f.indented=f.lexical.indented),f.lexical=f.lexical.prev)}xe.lex=!0;function Me(f){function m(U){return U==f?c():f==";"||U=="}"||U==")"||U=="]"?G():c(m)}return m}function Fe(f,m){return f=="var"?c(le("vardef",m),Er,Me(";"),xe):f=="keyword a"?c(le("form"),qe,Fe,xe):f=="keyword b"?c(le("form"),Fe,xe):f=="keyword d"?F.stream.match(/^\s*$/,!1)?c():c(le("stat"),dt,Me(";"),xe):f=="debugger"?c(Me(";")):f=="{"?c(le("}"),fe,Pt,xe,Te):f==";"?c():f=="if"?(F.state.lexical.info=="else"&&F.state.cc[F.state.cc.length-1]==xe&&F.state.cc.pop()(),c(le("form"),qe,Fe,xe,Or)):f=="function"?c(zt):f=="for"?c(le("form"),fe,Rn,Fe,Te,xe):f=="class"||Y&&m=="interface"?(F.marked="keyword",c(le("form",f=="class"?f:m),Pr,xe)):f=="variable"?Y&&m=="declare"?(F.marked="keyword",c(Fe)):Y&&(m=="module"||m=="enum"||m=="type")&&F.stream.match(/^\s*\w/,!1)?(F.marked="keyword",m=="enum"?c(ye):m=="type"?c(Wn,Me("operator"),Re,Me(";")):c(le("form"),kt,Me("{"),le("}"),Pt,xe,xe)):Y&&m=="namespace"?(F.marked="keyword",c(le("form"),ve,Fe,xe)):Y&&m=="abstract"?(F.marked="keyword",c(Fe)):c(le("stat"),ze):f=="switch"?c(le("form"),qe,Me("{"),le("}","switch"),fe,Pt,xe,xe,Te):f=="case"?c(ve,Me(":")):f=="default"?c(Me(":")):f=="catch"?c(le("form"),d,Ce,Fe,xe,Te):f=="export"?c(le("stat"),Ir,xe):f=="import"?c(le("stat"),fr,xe):f=="async"?c(Fe):m=="@"?c(ve,Fe):G(le("stat"),ve,Me(";"),xe)}function Ce(f){if(f=="(")return c(Wt,Me(")"))}function ve(f,m){return $e(f,m,!1)}function Oe(f,m){return $e(f,m,!0)}function qe(f){return f!="("?G():c(le(")"),dt,Me(")"),xe)}function $e(f,m,U){if(F.state.fatArrowAt==F.stream.start){var re=U?Ie:we;if(f=="(")return c(d,le(")"),Ne(Wt,")"),xe,Me("=>"),re,Te);if(f=="variable")return G(d,kt,Me("=>"),re,Te)}var B=U?_e:Pe;return W.hasOwnProperty(f)?c(B):f=="function"?c(zt,B):f=="class"||Y&&m=="interface"?(F.marked="keyword",c(le("form"),yi,xe)):f=="keyword c"||f=="async"?c(U?Oe:ve):f=="("?c(le(")"),dt,Me(")"),xe,B):f=="operator"||f=="spread"?c(U?Oe:ve):f=="["?c(le("]"),Je,xe,B):f=="{"?Mt(De,"}",null,B):f=="quasi"?G(Ue,B):f=="new"?c(E(U)):c()}function dt(f){return f.match(/[;\}\)\],]/)?G():G(ve)}function Pe(f,m){return f==","?c(dt):_e(f,m,!1)}function _e(f,m,U){var re=U==!1?Pe:_e,B=U==!1?ve:Oe;if(f=="=>")return c(d,U?Ie:we,Te);if(f=="operator")return/\+\+|--/.test(m)||Y&&m=="!"?c(re):Y&&m=="<"&&F.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?c(le(">"),Ne(Re,">"),xe,re):m=="?"?c(ve,Me(":"),B):c(B);if(f=="quasi")return G(Ue,re);if(f!=";"){if(f=="(")return Mt(Oe,")","call",re);if(f==".")return c(me,re);if(f=="[")return c(le("]"),dt,Me("]"),xe,re);if(Y&&m=="as")return F.marked="keyword",c(Re,re);if(f=="regexp")return F.state.lastType=F.marked="operator",F.stream.backUp(F.stream.pos-F.stream.start-1),c(B)}}function Ue(f,m){return f!="quasi"?G():m.slice(m.length-2)!="${"?c(Ue):c(dt,et)}function et(f){if(f=="}")return F.marked="string-2",F.state.tokenize=X,c(Ue)}function we(f){return p(F.stream,F.state),G(f=="{"?Fe:ve)}function Ie(f){return p(F.stream,F.state),G(f=="{"?Fe:Oe)}function E(f){return function(m){return m=="."?c(f?K:ee):m=="variable"&&Y?c(Ft,f?_e:Pe):G(f?Oe:ve)}}function ee(f,m){if(m=="target")return F.marked="keyword",c(Pe)}function K(f,m){if(m=="target")return F.marked="keyword",c(_e)}function ze(f){return f==":"?c(xe,Fe):G(Pe,Me(";"),xe)}function me(f){if(f=="variable")return F.marked="property",c()}function De(f,m){if(f=="async")return F.marked="property",c(De);if(f=="variable"||F.style=="keyword"){if(F.marked="property",m=="get"||m=="set")return c(be);var U;return Y&&F.state.fatArrowAt==F.stream.start&&(U=F.stream.match(/^\s*:\s*/,!1))&&(F.state.fatArrowAt=F.stream.pos+U[0].length),c(Be)}else{if(f=="number"||f=="string")return F.marked=Q?"property":F.style+" property",c(Be);if(f=="jsonld-keyword")return c(Be);if(Y&&y(m))return F.marked="keyword",c(De);if(f=="[")return c(ve,or,Me("]"),Be);if(f=="spread")return c(Oe,Be);if(m=="*")return F.marked="keyword",c(De);if(f==":")return G(Be)}}function be(f){return f!="variable"?G(Be):(F.marked="property",c(zt))}function Be(f){if(f==":")return c(Oe);if(f=="(")return G(zt)}function Ne(f,m,U){function re(B,ce){if(U?U.indexOf(B)>-1:B==","){var We=F.state.lexical;return We.info=="call"&&(We.pos=(We.pos||0)+1),c(function(it,wt){return it==m||wt==m?G():G(f)},re)}return B==m||ce==m?c():U&&U.indexOf(";")>-1?G(f):c(Me(m))}return function(B,ce){return B==m||ce==m?c():G(f,re)}}function Mt(f,m,U){for(var re=3;re"),Re);if(f=="quasi")return G(ht,It)}function Bn(f){if(f=="=>")return c(Re)}function Se(f){return f.match(/[\}\)\]]/)?c():f==","||f==";"?c(Se):G(Zt,Se)}function Zt(f,m){if(f=="variable"||F.style=="keyword")return F.marked="property",c(Zt);if(m=="?"||f=="number"||f=="string")return c(Zt);if(f==":")return c(Re);if(f=="[")return c(Me("variable"),br,Me("]"),Zt);if(f=="(")return G(ur,Zt);if(!f.match(/[;\}\)\],]/))return c()}function ht(f,m){return f!="quasi"?G():m.slice(m.length-2)!="${"?c(ht):c(Re,Ye)}function Ye(f){if(f=="}")return F.marked="string-2",F.state.tokenize=X,c(ht)}function Qe(f,m){return f=="variable"&&F.stream.match(/^\s*[?:]/,!1)||m=="?"?c(Qe):f==":"?c(Re):f=="spread"?c(Qe):G(Re)}function It(f,m){if(m=="<")return c(le(">"),Ne(Re,">"),xe,It);if(m=="|"||f=="."||m=="&")return c(Re);if(f=="[")return c(Re,Me("]"),It);if(m=="extends"||m=="implements")return F.marked="keyword",c(Re);if(m=="?")return c(Re,Me(":"),Re)}function Ft(f,m){if(m=="<")return c(le(">"),Ne(Re,">"),xe,It)}function Bt(){return G(Re,pt)}function pt(f,m){if(m=="=")return c(Re)}function Er(f,m){return m=="enum"?(F.marked="keyword",c(ye)):G(kt,or,Rt,xi)}function kt(f,m){if(Y&&y(m))return F.marked="keyword",c(kt);if(f=="variable")return C(m),c();if(f=="spread")return c(kt);if(f=="[")return Mt(ln,"]");if(f=="{")return Mt(ar,"}")}function ar(f,m){return f=="variable"&&!F.stream.match(/^\s*:/,!1)?(C(m),c(Rt)):(f=="variable"&&(F.marked="property"),f=="spread"?c(kt):f=="}"?G():f=="["?c(ve,Me("]"),Me(":"),ar):c(Me(":"),kt,Rt))}function ln(){return G(kt,Rt)}function Rt(f,m){if(m=="=")return c(Oe)}function xi(f){if(f==",")return c(Er)}function Or(f,m){if(f=="keyword b"&&m=="else")return c(le("form","else"),Fe,xe)}function Rn(f,m){if(m=="await")return c(Rn);if(f=="(")return c(le(")"),an,xe)}function an(f){return f=="var"?c(Er,sr):f=="variable"?c(sr):G(sr)}function sr(f,m){return f==")"?c():f==";"?c(sr):m=="in"||m=="of"?(F.marked="keyword",c(ve,sr)):G(ve,sr)}function zt(f,m){if(m=="*")return F.marked="keyword",c(zt);if(f=="variable")return C(m),c(zt);if(f=="(")return c(d,le(")"),Ne(Wt,")"),xe,lr,Fe,Te);if(Y&&m=="<")return c(le(">"),Ne(Bt,">"),xe,zt)}function ur(f,m){if(m=="*")return F.marked="keyword",c(ur);if(f=="variable")return C(m),c(ur);if(f=="(")return c(d,le(")"),Ne(Wt,")"),xe,lr,Te);if(Y&&m=="<")return c(le(">"),Ne(Bt,">"),xe,ur)}function Wn(f,m){if(f=="keyword"||f=="variable")return F.marked="type",c(Wn);if(m=="<")return c(le(">"),Ne(Bt,">"),xe)}function Wt(f,m){return m=="@"&&c(ve,Wt),f=="spread"?c(Wt):Y&&y(m)?(F.marked="keyword",c(Wt)):Y&&f=="this"?c(or,Rt):G(kt,or,Rt)}function yi(f,m){return f=="variable"?Pr(f,m):Ht(f,m)}function Pr(f,m){if(f=="variable")return C(m),c(Ht)}function Ht(f,m){if(m=="<")return c(le(">"),Ne(Bt,">"),xe,Ht);if(m=="extends"||m=="implements"||Y&&f==",")return m=="implements"&&(F.marked="keyword"),c(Y?Re:ve,Ht);if(f=="{")return c(le("}"),_t,xe)}function _t(f,m){if(f=="async"||f=="variable"&&(m=="static"||m=="get"||m=="set"||Y&&y(m))&&F.stream.match(/^\s+#?[\w$\xa1-\uffff]/,!1))return F.marked="keyword",c(_t);if(f=="variable"||F.style=="keyword")return F.marked="property",c(kr,_t);if(f=="number"||f=="string")return c(kr,_t);if(f=="[")return c(ve,or,Me("]"),kr,_t);if(m=="*")return F.marked="keyword",c(_t);if(Y&&f=="(")return G(ur,_t);if(f==";"||f==",")return c(_t);if(f=="}")return c();if(m=="@")return c(ve,_t)}function kr(f,m){if(m=="!"||m=="?")return c(kr);if(f==":")return c(Re,Rt);if(m=="=")return c(Oe);var U=F.state.lexical.prev,re=U&&U.info=="interface";return G(re?ur:zt)}function Ir(f,m){return m=="*"?(F.marked="keyword",c(Rr,Me(";"))):m=="default"?(F.marked="keyword",c(ve,Me(";"))):f=="{"?c(Ne(zr,"}"),Rr,Me(";")):G(Fe)}function zr(f,m){if(m=="as")return F.marked="keyword",c(Me("variable"));if(f=="variable")return G(Oe,zr)}function fr(f){return f=="string"?c():f=="("?G(ve):f=="."?G(Pe):G(Br,Gt,Rr)}function Br(f,m){return f=="{"?Mt(Br,"}"):(f=="variable"&&C(m),m=="*"&&(F.marked="keyword"),c(sn))}function Gt(f){if(f==",")return c(Br,Gt)}function sn(f,m){if(m=="as")return F.marked="keyword",c(Br)}function Rr(f,m){if(m=="from")return F.marked="keyword",c(ve)}function Je(f){return f=="]"?c():G(Ne(Oe,"]"))}function ye(){return G(le("form"),kt,Me("{"),le("}"),Ne($t,"}"),xe,xe)}function $t(){return G(kt,Rt)}function un(f,m){return f.lastType=="operator"||f.lastType==","||R.test(m.charAt(0))||/[,.]/.test(m.charAt(0))}function Et(f,m,U){return m.tokenize==M&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(m.lastType)||m.lastType=="quasi"&&/\{\s*$/.test(f.string.slice(0,f.pos-(U||0)))}return{startState:function(f){var m={tokenize:M,lastType:"sof",cc:[],lexical:new J((f||0)-te,0,"block",!1),localVars:_.localVars,context:_.localVars&&new j(null,null,!1),indented:f||0};return _.globalVars&&typeof _.globalVars=="object"&&(m.globalVars=_.globalVars),m},token:function(f,m){if(f.sol()&&(m.lexical.hasOwnProperty("align")||(m.lexical.align=!1),m.indented=f.indentation(),p(f,m)),m.tokenize!=z&&f.eatSpace())return null;var U=m.tokenize(f,m);return ue=="comment"?U:(m.lastType=ue=="operator"&&(O=="++"||O=="--")?"incdec":ue,V(m,U,ue,O,f))},indent:function(f,m){if(f.tokenize==z||f.tokenize==X)return b.Pass;if(f.tokenize!=M)return 0;var U=m&&m.charAt(0),re=f.lexical,B;if(!/^\s*else\b/.test(m))for(var ce=f.cc.length-1;ce>=0;--ce){var We=f.cc[ce];if(We==xe)re=re.prev;else if(We!=Or&&We!=Te)break}for(;(re.type=="stat"||re.type=="form")&&(U=="}"||(B=f.cc[f.cc.length-1])&&(B==Pe||B==_e)&&!/^[,\.=+\-*:?[\(]/.test(m));)re=re.prev;oe&&re.type==")"&&re.prev.type=="stat"&&(re=re.prev);var it=re.type,wt=U==it;return it=="vardef"?re.indented+(f.lastType=="operator"||f.lastType==","?re.info.length+1:0):it=="form"&&U=="{"?re.indented:it=="form"?re.indented+te:it=="stat"?re.indented+(un(f,m)?oe||te:0):re.info=="switch"&&!wt&&_.doubleIndentSwitch!=!1?re.indented+(/^(?:case|default)\b/.test(m)?te:2*te):re.align?re.column+(wt?0:1):re.indented+(wt?0:te)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:k?null:"/*",blockCommentEnd:k?null:"*/",blockCommentContinue:k?null:" * ",lineComment:k?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:k?"json":"javascript",jsonldMode:Q,jsonMode:k,expressionAllowed:Et,skipExpression:function(f){V(f,"atom","atom","true",new b.StringStream("",2,null))}}}),b.registerHelper("wordChars","javascript",/[\w$]/),b.defineMIME("text/javascript","javascript"),b.defineMIME("text/ecmascript","javascript"),b.defineMIME("application/javascript","javascript"),b.defineMIME("application/x-javascript","javascript"),b.defineMIME("application/ecmascript","javascript"),b.defineMIME("application/json",{name:"javascript",json:!0}),b.defineMIME("application/x-json",{name:"javascript",json:!0}),b.defineMIME("application/manifest+json",{name:"javascript",json:!0}),b.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),b.defineMIME("text/typescript",{name:"javascript",typescript:!0}),b.defineMIME("application/typescript",{name:"javascript",typescript:!0})})})()),ba.exports}var wa;function Vu(){return wa||(wa=1,(function(ct,xt){(function(b){b(mt(),Ya(),Qa(),Xa())})(function(b){var pe={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],[null,null,"css"]]};function _(ne,S,R){var A=ne.current(),$=A.search(S);return $>-1?ne.backUp(A.length-$):A.match(/<\/?$/)&&(ne.backUp(A.length),ne.match(S,!1)||ne.match(A)),R}var te={};function oe(ne){var S=te[ne];return S||(te[ne]=new RegExp("\\s+"+ne+`\\s*=\\s*('|")?([^'"]+)('|")?\\s*`))}function Q(ne,S){var R=ne.match(oe(S));return R?/^\s*(.*?)\s*$/.exec(R[2])[1]:""}function k(ne,S){return new RegExp((S?"^":"")+"","i")}function I(ne,S){for(var R in ne)for(var A=S[R]||(S[R]=[]),$=ne[R],ue=$.length-1;ue>=0;ue--)A.unshift($[ue])}function Y(ne,S){for(var R=0;R=0;O--)A.script.unshift(["type",ue[O].matches,ue[O].mode]);function w(M,N){var z=R.token(M,N.htmlState),X=/\btag\b/.test(z),q;if(X&&!/[<>\s\/]/.test(M.current())&&(q=N.htmlState.tagName&&N.htmlState.tagName.toLowerCase())&&A.hasOwnProperty(q))N.inTag=q+" ";else if(N.inTag&&X&&/>$/.test(M.current())){var p=/^([\S]+) (.*)/.exec(N.inTag);N.inTag=null;var W=M.current()==">"&&Y(A[p[1]],p[2]),J=b.getMode(ne,W),P=k(p[1],!0),V=k(p[1],!1);N.token=function(F,G){return F.match(P,!1)?(G.token=w,G.localState=G.localMode=null,null):_(F,V,G.localMode.token(F,G.localState))},N.localMode=J,N.localState=b.startState(J,R.indent(N.htmlState,"",""))}else N.inTag&&(N.inTag+=M.current(),M.eol()&&(N.inTag+=" "));return z}return{startState:function(){var M=b.startState(R);return{token:w,inTag:null,localMode:null,localState:null,htmlState:M}},copyState:function(M){var N;return M.localState&&(N=b.copyState(M.localMode,M.localState)),{token:M.token,inTag:M.inTag,localMode:M.localMode,localState:N,htmlState:b.copyState(R,M.htmlState)}},token:function(M,N){return N.token(M,N)},indent:function(M,N,z){return!M.localMode||/^\s*<\//.test(N)?R.indent(M.htmlState,N,z):M.localMode.indent?M.localMode.indent(M.localState,N,z):b.Pass},innerMode:function(M){return{state:M.localState||M.htmlState,mode:M.localMode||R}}}},"xml","javascript","css"),b.defineMIME("text/html","htmlmixed")})})()),ma.exports}Vu();Qa();var Sa={exports:{}},La;function ef(){return La||(La=1,(function(ct,xt){(function(b){b(mt())})(function(b){function pe(I){return new RegExp("^(("+I.join(")|(")+"))\\b")}var _=pe(["and","or","not","is"]),te=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in","False","True"],oe=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"];b.registerHelper("hintWords","python",te.concat(oe).concat(["exec","print"]));function Q(I){return I.scopes[I.scopes.length-1]}b.defineMode("python",function(I,Y){for(var ne="error",S=Y.delimiters||Y.singleDelimiters||/^[\(\)\[\]\{\}@,:`=;\.\\]/,R=[Y.singleOperators,Y.doubleOperators,Y.doubleDelimiters,Y.tripleDelimiters,Y.operators||/^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@]|\.\.\.)/],A=0;Ay?P(C):j0&&F(T,C)&&(de+=" "+ne),de}}return p(T,C)}function p(T,C,g){if(T.eatSpace())return null;if(!g&&T.match(/^#.*/))return"comment";if(T.match(/^[0-9\.]/,!1)){var y=!1;if(T.match(/^[\d_]*\.\d+(e[\+\-]?\d+)?/i)&&(y=!0),T.match(/^[\d_]+\.\d*/)&&(y=!0),T.match(/^\.\d+/)&&(y=!0),y)return T.eat(/J/i),"number";var j=!1;if(T.match(/^0x[0-9a-f_]+/i)&&(j=!0),T.match(/^0b[01_]+/i)&&(j=!0),T.match(/^0o[0-7_]+/i)&&(j=!0),T.match(/^[1-9][\d_]*(e[\+\-]?[\d_]+)?/)&&(T.eat(/J/i),j=!0),T.match(/^0(?![\dx])/i)&&(j=!0),j)return T.eat(/L/i),"number"}if(T.match(N)){var de=T.current().toLowerCase().indexOf("f")!==-1;return de?(C.tokenize=W(T.current(),C.tokenize),C.tokenize(T,C)):(C.tokenize=J(T.current(),C.tokenize),C.tokenize(T,C))}for(var v=0;v=0;)T=T.substr(1);var g=T.length==1,y="string";function j(v){return function(d,fe){var Te=p(d,fe,!0);return Te=="punctuation"&&(d.current()=="{"?fe.tokenize=j(v+1):d.current()=="}"&&(v>1?fe.tokenize=j(v-1):fe.tokenize=de)),Te}}function de(v,d){for(;!v.eol();)if(v.eatWhile(/[^'"\{\}\\]/),v.eat("\\")){if(v.next(),g&&v.eol())return y}else{if(v.match(T))return d.tokenize=C,y;if(v.match("{{"))return y;if(v.match("{",!1))return d.tokenize=j(0),v.current()?y:d.tokenize(v,d);if(v.match("}}"))return y;if(v.match("}"))return ne;v.eat(/['"]/)}if(g){if(Y.singleLineStringErrors)return ne;d.tokenize=C}return y}return de.isString=!0,de}function J(T,C){for(;"rubf".indexOf(T.charAt(0).toLowerCase())>=0;)T=T.substr(1);var g=T.length==1,y="string";function j(de,v){for(;!de.eol();)if(de.eatWhile(/[^'"\\]/),de.eat("\\")){if(de.next(),g&&de.eol())return y}else{if(de.match(T))return v.tokenize=C,y;de.eat(/['"]/)}if(g){if(Y.singleLineStringErrors)return ne;v.tokenize=C}return y}return j.isString=!0,j}function P(T){for(;Q(T).type!="py";)T.scopes.pop();T.scopes.push({offset:Q(T).offset+I.indentUnit,type:"py",align:null})}function V(T,C,g){var y=T.match(/^[\s\[\{\(]*(?:#|$)/,!1)?null:T.column()+1;C.scopes.push({offset:C.indent+$,type:g,align:y})}function F(T,C){for(var g=T.indentation();C.scopes.length>1&&Q(C).offset>g;){if(Q(C).type!="py")return!0;C.scopes.pop()}return Q(C).offset!=g}function G(T,C){T.sol()&&(C.beginningOfLine=!0,C.dedent=!1);var g=C.tokenize(T,C),y=T.current();if(C.beginningOfLine&&y=="@")return T.match(M,!1)?"meta":w?"operator":ne;if(/\S/.test(y)&&(C.beginningOfLine=!1),(g=="variable"||g=="builtin")&&C.lastToken=="meta"&&(g="meta"),(y=="pass"||y=="return")&&(C.dedent=!0),y=="lambda"&&(C.lambda=!0),y==":"&&!C.lambda&&Q(C).type=="py"&&T.match(/^\s*(?:#|$)/,!1)&&P(C),y.length==1&&!/string|comment/.test(g)){var j="[({".indexOf(y);if(j!=-1&&V(T,C,"])}".slice(j,j+1)),j="])}".indexOf(y),j!=-1)if(Q(C).type==y)C.indent=C.scopes.pop().offset-$;else return ne}return C.dedent&&T.eol()&&Q(C).type=="py"&&C.scopes.length>1&&C.scopes.pop(),g}var c={startState:function(T){return{tokenize:q,scopes:[{offset:T||0,type:"py",align:null}],indent:T||0,lastToken:null,lambda:!1,dedent:0}},token:function(T,C){var g=C.errorToken;g&&(C.errorToken=!1);var y=G(T,C);return y&&y!="comment"&&(C.lastToken=y=="keyword"||y=="punctuation"?T.current():y),y=="punctuation"&&(y=null),T.eol()&&C.lambda&&(C.lambda=!1),g?y+" "+ne:y},indent:function(T,C){if(T.tokenize!=q)return T.tokenize.isString?b.Pass:0;var g=Q(T),y=g.type==C.charAt(0)||g.type=="py"&&!T.dedent&&/^(else:|elif |except |finally:)/.test(C);return g.align!=null?g.align-(y?1:0):g.offset-(y?$:0)},electricInput:/^\s*([\}\]\)]|else:|elif |except |finally:)$/,closeBrackets:{triples:`'"`},lineComment:"#",fold:"indent"};return c}),b.defineMIME("text/x-python","python");var k=function(I){return I.split(" ")};b.defineMIME("text/x-cython",{name:"python",extra_keywords:k("by cdef cimport cpdef ctypedef enum except extern gil include nogil property public readonly struct union DEF IF ELIF ELSE")})})})()),Sa.exports}ef();var Ta={exports:{}},Ca;function tf(){return Ca||(Ca=1,(function(ct,xt){(function(b){b(mt())})(function(b){function pe(g,y,j,de,v,d){this.indented=g,this.column=y,this.type=j,this.info=de,this.align=v,this.prev=d}function _(g,y,j,de){var v=g.indented;return g.context&&g.context.type=="statement"&&j!="statement"&&(v=g.context.indented),g.context=new pe(v,y,j,de,null,g.context)}function te(g){var y=g.context.type;return(y==")"||y=="]"||y=="}")&&(g.indented=g.context.indented),g.context=g.context.prev}function oe(g,y,j){if(y.prevToken=="variable"||y.prevToken=="type"||/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(g.string.slice(0,j))||y.typeAtEndOfLine&&g.column()==g.indentation())return!0}function Q(g){for(;;){if(!g||g.type=="top")return!0;if(g.type=="}"&&g.prev.info!="namespace")return!1;g=g.prev}}b.defineMode("clike",function(g,y){var j=g.indentUnit,de=y.statementIndentUnit||j,v=y.dontAlignCalls,d=y.keywords||{},fe=y.types||{},Te=y.builtin||{},le=y.blockKeywords||{},xe=y.defKeywords||{},Me=y.atoms||{},Fe=y.hooks||{},Ce=y.multiLineStrings,ve=y.indentStatements!==!1,Oe=y.indentSwitch!==!1,qe=y.namespaceSeparator,$e=y.isPunctuationChar||/[\[\]{}\(\),;\:\.]/,dt=y.numberStart||/[\d\.]/,Pe=y.number||/^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,_e=y.isOperatorChar||/[+\-*&%=<>!?|\/]/,Ue=y.isIdentifierChar||/[\w\$_\xa1-\uffff]/,et=y.isReservedIdentifier||!1,we,Ie;function E(me,De){var be=me.next();if(Fe[be]){var Be=Fe[be](me,De);if(Be!==!1)return Be}if(be=='"'||be=="'")return De.tokenize=ee(be),De.tokenize(me,De);if(dt.test(be)){if(me.backUp(1),me.match(Pe))return"number";me.next()}if($e.test(be))return we=be,null;if(be=="/"){if(me.eat("*"))return De.tokenize=K,K(me,De);if(me.eat("/"))return me.skipToEnd(),"comment"}if(_e.test(be)){for(;!me.match(/^\/[\/*]/,!1)&&me.eat(_e););return"operator"}if(me.eatWhile(Ue),qe)for(;me.match(qe);)me.eatWhile(Ue);var Ne=me.current();return I(d,Ne)?(I(le,Ne)&&(we="newstatement"),I(xe,Ne)&&(Ie=!0),"keyword"):I(fe,Ne)?"type":I(Te,Ne)||et&&et(Ne)?(I(le,Ne)&&(we="newstatement"),"builtin"):I(Me,Ne)?"atom":"variable"}function ee(me){return function(De,be){for(var Be=!1,Ne,Mt=!1;(Ne=De.next())!=null;){if(Ne==me&&!Be){Mt=!0;break}Be=!Be&&Ne=="\\"}return(Mt||!(Be||Ce))&&(be.tokenize=null),"string"}}function K(me,De){for(var be=!1,Be;Be=me.next();){if(Be=="/"&&be){De.tokenize=null;break}be=Be=="*"}return"comment"}function ze(me,De){y.typeFirstDefinitions&&me.eol()&&Q(De.context)&&(De.typeAtEndOfLine=oe(me,De,me.pos))}return{startState:function(me){return{tokenize:null,context:new pe((me||0)-j,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(me,De){var be=De.context;if(me.sol()&&(be.align==null&&(be.align=!1),De.indented=me.indentation(),De.startOfLine=!0),me.eatSpace())return ze(me,De),null;we=Ie=null;var Be=(De.tokenize||E)(me,De);if(Be=="comment"||Be=="meta")return Be;if(be.align==null&&(be.align=!0),we==";"||we==":"||we==","&&me.match(/^\s*(?:\/\/.*)?$/,!1))for(;De.context.type=="statement";)te(De);else if(we=="{")_(De,me.column(),"}");else if(we=="[")_(De,me.column(),"]");else if(we=="(")_(De,me.column(),")");else if(we=="}"){for(;be.type=="statement";)be=te(De);for(be.type=="}"&&(be=te(De));be.type=="statement";)be=te(De)}else we==be.type?te(De):ve&&((be.type=="}"||be.type=="top")&&we!=";"||be.type=="statement"&&we=="newstatement")&&_(De,me.column(),"statement",me.current());if(Be=="variable"&&(De.prevToken=="def"||y.typeFirstDefinitions&&oe(me,De,me.start)&&Q(De.context)&&me.match(/^\s*\(/,!1))&&(Be="def"),Fe.token){var Ne=Fe.token(me,De,Be);Ne!==void 0&&(Be=Ne)}return Be=="def"&&y.styleDefs===!1&&(Be="variable"),De.startOfLine=!1,De.prevToken=Ie?"def":Be||we,ze(me,De),Be},indent:function(me,De){if(me.tokenize!=E&&me.tokenize!=null||me.typeAtEndOfLine&&Q(me.context))return b.Pass;var be=me.context,Be=De&&De.charAt(0),Ne=Be==be.type;if(be.type=="statement"&&Be=="}"&&(be=be.prev),y.dontIndentStatements)for(;be.type=="statement"&&y.dontIndentStatements.test(be.info);)be=be.prev;if(Fe.indent){var Mt=Fe.indent(me,be,De,j);if(typeof Mt=="number")return Mt}var Pt=be.prev&&be.prev.info=="switch";if(y.allmanIndentation&&/[{(]/.test(Be)){for(;be.type!="top"&&be.type!="}";)be=be.prev;return be.indented}return be.type=="statement"?be.indented+(Be=="{"?0:de):be.align&&(!v||be.type!=")")?be.column+(Ne?0:1):be.type==")"&&!Ne?be.indented+de:be.indented+(Ne?0:j)+(!Ne&&Pt&&!/^(?:case|default)\b/.test(De)?j:0)},electricInput:Oe?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace"}});function k(g){for(var y={},j=g.split(" "),de=0;de!?|\/#:@]/,hooks:{"@":function(g){return g.eatWhile(/[\w\$_]/),"meta"},'"':function(g,y){return g.match('""')?(y.tokenize=F,y.tokenize(g,y)):!1},"'":function(g){return g.match(/^(\\[^'\s]+|[^\\'])'/)?"string-2":(g.eatWhile(/[\w\$_\xa1-\uffff]/),"atom")},"=":function(g,y){var j=y.context;return j.type=="}"&&j.align&&g.eat(">")?(y.context=new pe(j.indented,j.column,j.type,j.info,null,j.prev),"operator"):!1},"/":function(g,y){return g.eat("*")?(y.tokenize=G(1),y.tokenize(g,y)):!1}},modeProps:{closeBrackets:{pairs:'()[]{}""',triples:'"'}}});function c(g){return function(y,j){for(var de=!1,v,d=!1;!y.eol();){if(!g&&!de&&y.match('"')){d=!0;break}if(g&&y.match('"""')){d=!0;break}v=y.next(),!de&&v=="$"&&y.match("{")&&y.skipTo("}"),de=!de&&v=="\\"&&!g}return(d||!g)&&(j.tokenize=null),"string"}}V("text/x-kotlin",{name:"clike",keywords:k("package as typealias class interface this super val operator var fun for is in This throw return annotation break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend actual expect setparam value"),types:k("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy LazyThreadSafetyMode LongArray Nothing ShortArray Unit"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:k("catch class do else finally for if where try while enum"),defKeywords:k("class val var object interface fun"),atoms:k("true false null this"),hooks:{"@":function(g){return g.eatWhile(/[\w\$_]/),"meta"},"*":function(g,y){return y.prevToken=="."?"variable":"operator"},'"':function(g,y){return y.tokenize=c(g.match('""')),y.tokenize(g,y)},"/":function(g,y){return g.eat("*")?(y.tokenize=G(1),y.tokenize(g,y)):!1},indent:function(g,y,j,de){var v=j&&j.charAt(0);if((g.prevToken=="}"||g.prevToken==")")&&j=="")return g.indented;if(g.prevToken=="operator"&&j!="}"&&g.context.type!="}"||g.prevToken=="variable"&&v=="."||(g.prevToken=="}"||g.prevToken==")")&&v==".")return de*2+y.indented;if(y.align&&y.type=="}")return y.indented+(g.context.type==(j||"").charAt(0)?0:de)}},modeProps:{closeBrackets:{triples:'"'}}}),V(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:k("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:k("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),blockKeywords:k("for while do if else struct"),builtin:k("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:k("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TextureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),indentSwitch:!1,hooks:{"#":N},modeProps:{fold:["brace","include"]}}),V("text/x-nesc",{name:"clike",keywords:k(Y+" as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:ue,blockKeywords:k(w),atoms:k("null true false"),hooks:{"#":N},modeProps:{fold:["brace","include"]}}),V("text/x-objectivec",{name:"clike",keywords:k(Y+" "+S),types:O,builtin:k(R),blockKeywords:k(w+" @synthesize @try @catch @finally @autoreleasepool @synchronized"),defKeywords:k(M+" @interface @implementation @protocol @class"),dontIndentStatements:/^@.*$/,typeFirstDefinitions:!0,atoms:k("YES NO NULL Nil nil true false nullptr"),isReservedIdentifier:X,hooks:{"#":N,"*":z},modeProps:{fold:["brace","include"]}}),V("text/x-objectivec++",{name:"clike",keywords:k(Y+" "+S+" "+ne),types:O,builtin:k(R),blockKeywords:k(w+" @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"),defKeywords:k(M+" @interface @implementation @protocol @class class namespace"),dontIndentStatements:/^@.*$|^template$/,typeFirstDefinitions:!0,atoms:k("YES NO NULL Nil nil true false nullptr"),isReservedIdentifier:X,hooks:{"#":N,"*":z,u:p,U:p,L:p,R:p,0:q,1:q,2:q,3:q,4:q,5:q,6:q,7:q,8:q,9:q,token:function(g,y,j){if(j=="variable"&&g.peek()=="("&&(y.prevToken==";"||y.prevToken==null||y.prevToken=="}")&&W(g.current()))return"def"}},namespaceSeparator:"::",modeProps:{fold:["brace","include"]}}),V("text/x-squirrel",{name:"clike",keywords:k("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),types:ue,blockKeywords:k("case catch class else for foreach if switch try while"),defKeywords:k("function local class"),typeFirstDefinitions:!0,atoms:k("true false null"),hooks:{"#":N},modeProps:{fold:["brace","include"]}});var T=null;function C(g){return function(y,j){for(var de=!1,v,d=!1;!y.eol();){if(!de&&y.match('"')&&(g=="single"||y.match('""'))){d=!0;break}if(!de&&y.match("``")){T=C(g),d=!0;break}v=y.next(),de=g=="single"&&!de&&v=="\\"}return d&&(j.tokenize=null),"string"}}V("text/x-ceylon",{name:"clike",keywords:k("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),types:function(g){var y=g.charAt(0);return y===y.toUpperCase()&&y!==y.toLowerCase()},blockKeywords:k("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:k("class dynamic function interface module object package value"),builtin:k("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:k("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(g){return g.eatWhile(/[\w\$_]/),"meta"},'"':function(g,y){return y.tokenize=C(g.match('""')?"triple":"single"),y.tokenize(g,y)},"`":function(g,y){return!T||!g.match("`")?!1:(y.tokenize=T,T=null,y.tokenize(g,y))},"'":function(g){return g.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(g,y,j){if((j=="variable"||j=="type")&&y.prevToken==".")return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})})})()),Ta.exports}tf();var Da={exports:{}},Ma={exports:{}},Fa;function rf(){return Fa||(Fa=1,(function(ct,xt){(function(b){b(mt())})(function(b){b.modeInfo=[{name:"APL",mime:"text/apl",mode:"apl",ext:["dyalog","apl"]},{name:"PGP",mimes:["application/pgp","application/pgp-encrypted","application/pgp-keys","application/pgp-signature"],mode:"asciiarmor",ext:["asc","pgp","sig"]},{name:"ASN.1",mime:"text/x-ttcn-asn",mode:"asn.1",ext:["asn","asn1"]},{name:"Asterisk",mime:"text/x-asterisk",mode:"asterisk",file:/^extensions\.conf$/i},{name:"Brainfuck",mime:"text/x-brainfuck",mode:"brainfuck",ext:["b","bf"]},{name:"C",mime:"text/x-csrc",mode:"clike",ext:["c","h","ino"]},{name:"C++",mime:"text/x-c++src",mode:"clike",ext:["cpp","c++","cc","cxx","hpp","h++","hh","hxx"],alias:["cpp"]},{name:"Cobol",mime:"text/x-cobol",mode:"cobol",ext:["cob","cpy","cbl"]},{name:"C#",mime:"text/x-csharp",mode:"clike",ext:["cs"],alias:["csharp","cs"]},{name:"Clojure",mime:"text/x-clojure",mode:"clojure",ext:["clj","cljc","cljx"]},{name:"ClojureScript",mime:"text/x-clojurescript",mode:"clojure",ext:["cljs"]},{name:"Closure Stylesheets (GSS)",mime:"text/x-gss",mode:"css",ext:["gss"]},{name:"CMake",mime:"text/x-cmake",mode:"cmake",ext:["cmake","cmake.in"],file:/^CMakeLists\.txt$/},{name:"CoffeeScript",mimes:["application/vnd.coffeescript","text/coffeescript","text/x-coffeescript"],mode:"coffeescript",ext:["coffee"],alias:["coffee","coffee-script"]},{name:"Common Lisp",mime:"text/x-common-lisp",mode:"commonlisp",ext:["cl","lisp","el"],alias:["lisp"]},{name:"Cypher",mime:"application/x-cypher-query",mode:"cypher",ext:["cyp","cypher"]},{name:"Cython",mime:"text/x-cython",mode:"python",ext:["pyx","pxd","pxi"]},{name:"Crystal",mime:"text/x-crystal",mode:"crystal",ext:["cr"]},{name:"CSS",mime:"text/css",mode:"css",ext:["css"]},{name:"CQL",mime:"text/x-cassandra",mode:"sql",ext:["cql"]},{name:"D",mime:"text/x-d",mode:"d",ext:["d"]},{name:"Dart",mimes:["application/dart","text/x-dart"],mode:"dart",ext:["dart"]},{name:"diff",mime:"text/x-diff",mode:"diff",ext:["diff","patch"]},{name:"Django",mime:"text/x-django",mode:"django"},{name:"Dockerfile",mime:"text/x-dockerfile",mode:"dockerfile",file:/^Dockerfile$/},{name:"DTD",mime:"application/xml-dtd",mode:"dtd",ext:["dtd"]},{name:"Dylan",mime:"text/x-dylan",mode:"dylan",ext:["dylan","dyl","intr"]},{name:"EBNF",mime:"text/x-ebnf",mode:"ebnf"},{name:"ECL",mime:"text/x-ecl",mode:"ecl",ext:["ecl"]},{name:"edn",mime:"application/edn",mode:"clojure",ext:["edn"]},{name:"Eiffel",mime:"text/x-eiffel",mode:"eiffel",ext:["e"]},{name:"Elm",mime:"text/x-elm",mode:"elm",ext:["elm"]},{name:"Embedded JavaScript",mime:"application/x-ejs",mode:"htmlembedded",ext:["ejs"]},{name:"Embedded Ruby",mime:"application/x-erb",mode:"htmlembedded",ext:["erb"]},{name:"Erlang",mime:"text/x-erlang",mode:"erlang",ext:["erl"]},{name:"Esper",mime:"text/x-esper",mode:"sql"},{name:"Factor",mime:"text/x-factor",mode:"factor",ext:["factor"]},{name:"FCL",mime:"text/x-fcl",mode:"fcl"},{name:"Forth",mime:"text/x-forth",mode:"forth",ext:["forth","fth","4th"]},{name:"Fortran",mime:"text/x-fortran",mode:"fortran",ext:["f","for","f77","f90","f95"]},{name:"F#",mime:"text/x-fsharp",mode:"mllike",ext:["fs"],alias:["fsharp"]},{name:"Gas",mime:"text/x-gas",mode:"gas",ext:["s"]},{name:"Gherkin",mime:"text/x-feature",mode:"gherkin",ext:["feature"]},{name:"GitHub Flavored Markdown",mime:"text/x-gfm",mode:"gfm",file:/^(readme|contributing|history)\.md$/i},{name:"Go",mime:"text/x-go",mode:"go",ext:["go"]},{name:"Groovy",mime:"text/x-groovy",mode:"groovy",ext:["groovy","gradle"],file:/^Jenkinsfile$/},{name:"HAML",mime:"text/x-haml",mode:"haml",ext:["haml"]},{name:"Haskell",mime:"text/x-haskell",mode:"haskell",ext:["hs"]},{name:"Haskell (Literate)",mime:"text/x-literate-haskell",mode:"haskell-literate",ext:["lhs"]},{name:"Haxe",mime:"text/x-haxe",mode:"haxe",ext:["hx"]},{name:"HXML",mime:"text/x-hxml",mode:"haxe",ext:["hxml"]},{name:"ASP.NET",mime:"application/x-aspx",mode:"htmlembedded",ext:["aspx"],alias:["asp","aspx"]},{name:"HTML",mime:"text/html",mode:"htmlmixed",ext:["html","htm","handlebars","hbs"],alias:["xhtml"]},{name:"HTTP",mime:"message/http",mode:"http"},{name:"IDL",mime:"text/x-idl",mode:"idl",ext:["pro"]},{name:"Pug",mime:"text/x-pug",mode:"pug",ext:["jade","pug"],alias:["jade"]},{name:"Java",mime:"text/x-java",mode:"clike",ext:["java"]},{name:"Java Server Pages",mime:"application/x-jsp",mode:"htmlembedded",ext:["jsp"],alias:["jsp"]},{name:"JavaScript",mimes:["text/javascript","text/ecmascript","application/javascript","application/x-javascript","application/ecmascript"],mode:"javascript",ext:["js"],alias:["ecmascript","js","node"]},{name:"JSON",mimes:["application/json","application/x-json"],mode:"javascript",ext:["json","map"],alias:["json5"]},{name:"JSON-LD",mime:"application/ld+json",mode:"javascript",ext:["jsonld"],alias:["jsonld"]},{name:"JSX",mime:"text/jsx",mode:"jsx",ext:["jsx"]},{name:"Jinja2",mime:"text/jinja2",mode:"jinja2",ext:["j2","jinja","jinja2"]},{name:"Julia",mime:"text/x-julia",mode:"julia",ext:["jl"],alias:["jl"]},{name:"Kotlin",mime:"text/x-kotlin",mode:"clike",ext:["kt"]},{name:"LESS",mime:"text/x-less",mode:"css",ext:["less"]},{name:"LiveScript",mime:"text/x-livescript",mode:"livescript",ext:["ls"],alias:["ls"]},{name:"Lua",mime:"text/x-lua",mode:"lua",ext:["lua"]},{name:"Markdown",mime:"text/x-markdown",mode:"markdown",ext:["markdown","md","mkd"]},{name:"mIRC",mime:"text/mirc",mode:"mirc"},{name:"MariaDB SQL",mime:"text/x-mariadb",mode:"sql"},{name:"Mathematica",mime:"text/x-mathematica",mode:"mathematica",ext:["m","nb","wl","wls"]},{name:"Modelica",mime:"text/x-modelica",mode:"modelica",ext:["mo"]},{name:"MUMPS",mime:"text/x-mumps",mode:"mumps",ext:["mps"]},{name:"MS SQL",mime:"text/x-mssql",mode:"sql"},{name:"mbox",mime:"application/mbox",mode:"mbox",ext:["mbox"]},{name:"MySQL",mime:"text/x-mysql",mode:"sql"},{name:"Nginx",mime:"text/x-nginx-conf",mode:"nginx",file:/nginx.*\.conf$/i},{name:"NSIS",mime:"text/x-nsis",mode:"nsis",ext:["nsh","nsi"]},{name:"NTriples",mimes:["application/n-triples","application/n-quads","text/n-triples"],mode:"ntriples",ext:["nt","nq"]},{name:"Objective-C",mime:"text/x-objectivec",mode:"clike",ext:["m"],alias:["objective-c","objc"]},{name:"Objective-C++",mime:"text/x-objectivec++",mode:"clike",ext:["mm"],alias:["objective-c++","objc++"]},{name:"OCaml",mime:"text/x-ocaml",mode:"mllike",ext:["ml","mli","mll","mly"]},{name:"Octave",mime:"text/x-octave",mode:"octave",ext:["m"]},{name:"Oz",mime:"text/x-oz",mode:"oz",ext:["oz"]},{name:"Pascal",mime:"text/x-pascal",mode:"pascal",ext:["p","pas"]},{name:"PEG.js",mime:"null",mode:"pegjs",ext:["jsonld"]},{name:"Perl",mime:"text/x-perl",mode:"perl",ext:["pl","pm"]},{name:"PHP",mimes:["text/x-php","application/x-httpd-php","application/x-httpd-php-open"],mode:"php",ext:["php","php3","php4","php5","php7","phtml"]},{name:"Pig",mime:"text/x-pig",mode:"pig",ext:["pig"]},{name:"Plain Text",mime:"text/plain",mode:"null",ext:["txt","text","conf","def","list","log"]},{name:"PLSQL",mime:"text/x-plsql",mode:"sql",ext:["pls"]},{name:"PostgreSQL",mime:"text/x-pgsql",mode:"sql"},{name:"PowerShell",mime:"application/x-powershell",mode:"powershell",ext:["ps1","psd1","psm1"]},{name:"Properties files",mime:"text/x-properties",mode:"properties",ext:["properties","ini","in"],alias:["ini","properties"]},{name:"ProtoBuf",mime:"text/x-protobuf",mode:"protobuf",ext:["proto"]},{name:"Python",mime:"text/x-python",mode:"python",ext:["BUILD","bzl","py","pyw"],file:/^(BUCK|BUILD)$/},{name:"Puppet",mime:"text/x-puppet",mode:"puppet",ext:["pp"]},{name:"Q",mime:"text/x-q",mode:"q",ext:["q"]},{name:"R",mime:"text/x-rsrc",mode:"r",ext:["r","R"],alias:["rscript"]},{name:"reStructuredText",mime:"text/x-rst",mode:"rst",ext:["rst"],alias:["rst"]},{name:"RPM Changes",mime:"text/x-rpm-changes",mode:"rpm"},{name:"RPM Spec",mime:"text/x-rpm-spec",mode:"rpm",ext:["spec"]},{name:"Ruby",mime:"text/x-ruby",mode:"ruby",ext:["rb"],alias:["jruby","macruby","rake","rb","rbx"]},{name:"Rust",mime:"text/x-rustsrc",mode:"rust",ext:["rs"]},{name:"SAS",mime:"text/x-sas",mode:"sas",ext:["sas"]},{name:"Sass",mime:"text/x-sass",mode:"sass",ext:["sass"]},{name:"Scala",mime:"text/x-scala",mode:"clike",ext:["scala"]},{name:"Scheme",mime:"text/x-scheme",mode:"scheme",ext:["scm","ss"]},{name:"SCSS",mime:"text/x-scss",mode:"css",ext:["scss"]},{name:"Shell",mimes:["text/x-sh","application/x-sh"],mode:"shell",ext:["sh","ksh","bash"],alias:["bash","sh","zsh"],file:/^PKGBUILD$/},{name:"Sieve",mime:"application/sieve",mode:"sieve",ext:["siv","sieve"]},{name:"Slim",mimes:["text/x-slim","application/x-slim"],mode:"slim",ext:["slim"]},{name:"Smalltalk",mime:"text/x-stsrc",mode:"smalltalk",ext:["st"]},{name:"Smarty",mime:"text/x-smarty",mode:"smarty",ext:["tpl"]},{name:"Solr",mime:"text/x-solr",mode:"solr"},{name:"SML",mime:"text/x-sml",mode:"mllike",ext:["sml","sig","fun","smackspec"]},{name:"Soy",mime:"text/x-soy",mode:"soy",ext:["soy"],alias:["closure template"]},{name:"SPARQL",mime:"application/sparql-query",mode:"sparql",ext:["rq","sparql"],alias:["sparul"]},{name:"Spreadsheet",mime:"text/x-spreadsheet",mode:"spreadsheet",alias:["excel","formula"]},{name:"SQL",mime:"text/x-sql",mode:"sql",ext:["sql"]},{name:"SQLite",mime:"text/x-sqlite",mode:"sql"},{name:"Squirrel",mime:"text/x-squirrel",mode:"clike",ext:["nut"]},{name:"Stylus",mime:"text/x-styl",mode:"stylus",ext:["styl"]},{name:"Swift",mime:"text/x-swift",mode:"swift",ext:["swift"]},{name:"sTeX",mime:"text/x-stex",mode:"stex"},{name:"LaTeX",mime:"text/x-latex",mode:"stex",ext:["text","ltx","tex"],alias:["tex"]},{name:"SystemVerilog",mime:"text/x-systemverilog",mode:"verilog",ext:["v","sv","svh"]},{name:"Tcl",mime:"text/x-tcl",mode:"tcl",ext:["tcl"]},{name:"Textile",mime:"text/x-textile",mode:"textile",ext:["textile"]},{name:"TiddlyWiki",mime:"text/x-tiddlywiki",mode:"tiddlywiki"},{name:"Tiki wiki",mime:"text/tiki",mode:"tiki"},{name:"TOML",mime:"text/x-toml",mode:"toml",ext:["toml"]},{name:"Tornado",mime:"text/x-tornado",mode:"tornado"},{name:"troff",mime:"text/troff",mode:"troff",ext:["1","2","3","4","5","6","7","8","9"]},{name:"TTCN",mime:"text/x-ttcn",mode:"ttcn",ext:["ttcn","ttcn3","ttcnpp"]},{name:"TTCN_CFG",mime:"text/x-ttcn-cfg",mode:"ttcn-cfg",ext:["cfg"]},{name:"Turtle",mime:"text/turtle",mode:"turtle",ext:["ttl"]},{name:"TypeScript",mime:"application/typescript",mode:"javascript",ext:["ts"],alias:["ts"]},{name:"TypeScript-JSX",mime:"text/typescript-jsx",mode:"jsx",ext:["tsx"],alias:["tsx"]},{name:"Twig",mime:"text/x-twig",mode:"twig"},{name:"Web IDL",mime:"text/x-webidl",mode:"webidl",ext:["webidl"]},{name:"VB.NET",mime:"text/x-vb",mode:"vb",ext:["vb"]},{name:"VBScript",mime:"text/vbscript",mode:"vbscript",ext:["vbs"]},{name:"Velocity",mime:"text/velocity",mode:"velocity",ext:["vtl"]},{name:"Verilog",mime:"text/x-verilog",mode:"verilog",ext:["v"]},{name:"VHDL",mime:"text/x-vhdl",mode:"vhdl",ext:["vhd","vhdl"]},{name:"Vue.js Component",mimes:["script/x-vue","text/x-vue"],mode:"vue",ext:["vue"]},{name:"XML",mimes:["application/xml","text/xml"],mode:"xml",ext:["xml","xsl","xsd","svg"],alias:["rss","wsdl","xsd"]},{name:"XQuery",mime:"application/xquery",mode:"xquery",ext:["xy","xquery"]},{name:"Yacas",mime:"text/x-yacas",mode:"yacas",ext:["ys"]},{name:"YAML",mimes:["text/x-yaml","text/yaml"],mode:"yaml",ext:["yaml","yml"],alias:["yml"]},{name:"Z80",mime:"text/x-z80",mode:"z80",ext:["z80"]},{name:"mscgen",mime:"text/x-mscgen",mode:"mscgen",ext:["mscgen","mscin","msc"]},{name:"xu",mime:"text/x-xu",mode:"mscgen",ext:["xu"]},{name:"msgenny",mime:"text/x-msgenny",mode:"mscgen",ext:["msgenny"]},{name:"WebAssembly",mime:"text/webassembly",mode:"wast",ext:["wat","wast"]}];for(var pe=0;pe-1&&te.substring(k+1,te.length);if(I)return b.findModeByExtension(I)},b.findModeByName=function(te){te=te.toLowerCase();for(var oe=0;oe` "'(~:]+/,ue=/^(~~~+|```+)[ \t]*([\w\/+#-]*)[^\n`]*$/,O=/^\s*\[[^\]]+?\]:.*$/,w=/[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/,M=" ";function N(v,d,fe){return d.f=d.inline=fe,fe(v,d)}function z(v,d,fe){return d.f=d.block=fe,fe(v,d)}function X(v){return!v||!/\S/.test(v.string)}function q(v){if(v.linkTitle=!1,v.linkHref=!1,v.linkText=!1,v.em=!1,v.strong=!1,v.strikethrough=!1,v.quote=0,v.indentedCode=!1,v.f==W){var d=oe;if(!d){var fe=b.innerMode(te,v.htmlState);d=fe.mode.name=="xml"&&fe.state.tagStart===null&&!fe.state.context&&fe.state.tokenize.isInText}d&&(v.f=F,v.block=p,v.htmlState=null)}return v.trailingSpace=0,v.trailingSpaceNewLine=!1,v.prevLine=v.thisLine,v.thisLine={stream:null},null}function p(v,d){var fe=v.column()===d.indentation,Te=X(d.prevLine.stream),le=d.indentedCode,xe=d.prevLine.hr,Me=d.list!==!1,Fe=(d.listStack[d.listStack.length-1]||0)+3;d.indentedCode=!1;var Ce=d.indentation;if(d.indentationDiff===null&&(d.indentationDiff=d.indentation,Me)){for(d.list=null;Ce=4&&(le||d.prevLine.fencedCodeEnd||d.prevLine.header||Te))return v.skipToEnd(),d.indentedCode=!0,k.code;if(v.eatSpace())return null;if(fe&&d.indentation<=Fe&&(qe=v.match(R))&&qe[1].length<=6)return d.quote=0,d.header=qe[1].length,d.thisLine.header=!0,_.highlightFormatting&&(d.formatting="header"),d.f=d.inline,P(d);if(d.indentation<=Fe&&v.eat(">"))return d.quote=fe?1:d.quote+1,_.highlightFormatting&&(d.formatting="quote"),v.eatSpace(),P(d);if(!Oe&&!d.setext&&fe&&d.indentation<=Fe&&(qe=v.match(ne))){var $e=qe[1]?"ol":"ul";return d.indentation=Ce+v.current().length,d.list=!0,d.quote=0,d.listStack.push(d.indentation),d.em=!1,d.strong=!1,d.code=!1,d.strikethrough=!1,_.taskLists&&v.match(S,!1)&&(d.taskList=!0),d.f=d.inline,_.highlightFormatting&&(d.formatting=["list","list-"+$e]),P(d)}else{if(fe&&d.indentation<=Fe&&(qe=v.match(ue,!0)))return d.quote=0,d.fencedEndRE=new RegExp(qe[1]+"+ *$"),d.localMode=_.fencedCodeBlockHighlighting&&Q(qe[2]||_.fencedCodeBlockDefaultMode),d.localMode&&(d.localState=b.startState(d.localMode)),d.f=d.block=J,_.highlightFormatting&&(d.formatting="code-block"),d.code=-1,P(d);if(d.setext||(!ve||!Me)&&!d.quote&&d.list===!1&&!d.code&&!Oe&&!O.test(v.string)&&(qe=v.lookAhead(1))&&(qe=qe.match(A)))return d.setext?(d.header=d.setext,d.setext=0,v.skipToEnd(),_.highlightFormatting&&(d.formatting="header")):(d.header=qe[0].charAt(0)=="="?1:2,d.setext=d.header),d.thisLine.header=!0,d.f=d.inline,P(d);if(Oe)return v.skipToEnd(),d.hr=!0,d.thisLine.hr=!0,k.hr;if(v.peek()==="[")return N(v,d,g)}return N(v,d,d.inline)}function W(v,d){var fe=te.token(v,d.htmlState);if(!oe){var Te=b.innerMode(te,d.htmlState);(Te.mode.name=="xml"&&Te.state.tagStart===null&&!Te.state.context&&Te.state.tokenize.isInText||d.md_inside&&v.current().indexOf(">")>-1)&&(d.f=F,d.block=p,d.htmlState=null)}return fe}function J(v,d){var fe=d.listStack[d.listStack.length-1]||0,Te=d.indentation=v.quote?d.push(k.formatting+"-"+v.formatting[fe]+"-"+v.quote):d.push("error"))}if(v.taskOpen)return d.push("meta"),d.length?d.join(" "):null;if(v.taskClosed)return d.push("property"),d.length?d.join(" "):null;if(v.linkHref?d.push(k.linkHref,"url"):(v.strong&&d.push(k.strong),v.em&&d.push(k.em),v.strikethrough&&d.push(k.strikethrough),v.emoji&&d.push(k.emoji),v.linkText&&d.push(k.linkText),v.code&&d.push(k.code),v.image&&d.push(k.image),v.imageAltText&&d.push(k.imageAltText,"link"),v.imageMarker&&d.push(k.imageMarker)),v.header&&d.push(k.header,k.header+"-"+v.header),v.quote&&(d.push(k.quote),!_.maxBlockquoteDepth||_.maxBlockquoteDepth>=v.quote?d.push(k.quote+"-"+v.quote):d.push(k.quote+"-"+_.maxBlockquoteDepth)),v.list!==!1){var Te=(v.listStack.length-1)%3;Te?Te===1?d.push(k.list2):d.push(k.list3):d.push(k.list1)}return v.trailingSpaceNewLine?d.push("trailing-space-new-line"):v.trailingSpace&&d.push("trailing-space-"+(v.trailingSpace%2?"a":"b")),d.length?d.join(" "):null}function V(v,d){if(v.match($,!0))return P(d)}function F(v,d){var fe=d.text(v,d);if(typeof fe<"u")return fe;if(d.list)return d.list=null,P(d);if(d.taskList){var Te=v.match(S,!0)[1]===" ";return Te?d.taskOpen=!0:d.taskClosed=!0,_.highlightFormatting&&(d.formatting="task"),d.taskList=!1,P(d)}if(d.taskOpen=!1,d.taskClosed=!1,d.header&&v.match(/^#+$/,!0))return _.highlightFormatting&&(d.formatting="header"),P(d);var le=v.next();if(d.linkTitle){d.linkTitle=!1;var xe=le;le==="("&&(xe=")"),xe=(xe+"").replace(/([.?*+^\[\]\\(){}|-])/g,"\\$1");var Me="^\\s*(?:[^"+xe+"\\\\]+|\\\\\\\\|\\\\.)"+xe;if(v.match(new RegExp(Me),!0))return k.linkHref}if(le==="`"){var Fe=d.formatting;_.highlightFormatting&&(d.formatting="code"),v.eatWhile("`");var Ce=v.current().length;if(d.code==0&&(!d.quote||Ce==1))return d.code=Ce,P(d);if(Ce==d.code){var ve=P(d);return d.code=0,ve}else return d.formatting=Fe,P(d)}else if(d.code)return P(d);if(le==="\\"&&(v.next(),_.highlightFormatting)){var Oe=P(d),qe=k.formatting+"-escape";return Oe?Oe+" "+qe:qe}if(le==="!"&&v.match(/\[[^\]]*\] ?(?:\(|\[)/,!1))return d.imageMarker=!0,d.image=!0,_.highlightFormatting&&(d.formatting="image"),P(d);if(le==="["&&d.imageMarker&&v.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/,!1))return d.imageMarker=!1,d.imageAltText=!0,_.highlightFormatting&&(d.formatting="image"),P(d);if(le==="]"&&d.imageAltText){_.highlightFormatting&&(d.formatting="image");var Oe=P(d);return d.imageAltText=!1,d.image=!1,d.inline=d.f=c,Oe}if(le==="["&&!d.image)return d.linkText&&v.match(/^.*?\]/)||(d.linkText=!0,_.highlightFormatting&&(d.formatting="link")),P(d);if(le==="]"&&d.linkText){_.highlightFormatting&&(d.formatting="link");var Oe=P(d);return d.linkText=!1,d.inline=d.f=v.match(/\(.*?\)| ?\[.*?\]/,!1)?c:F,Oe}if(le==="<"&&v.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/,!1)){d.f=d.inline=G,_.highlightFormatting&&(d.formatting="link");var Oe=P(d);return Oe?Oe+=" ":Oe="",Oe+k.linkInline}if(le==="<"&&v.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/,!1)){d.f=d.inline=G,_.highlightFormatting&&(d.formatting="link");var Oe=P(d);return Oe?Oe+=" ":Oe="",Oe+k.linkEmail}if(_.xml&&le==="<"&&v.match(/^(!--|\?|!\[CDATA\[|[a-z][a-z0-9-]*(?:\s+[a-z_:.\-]+(?:\s*=\s*[^>]+)?)*\s*(?:>|$))/i,!1)){var $e=v.string.indexOf(">",v.pos);if($e!=-1){var dt=v.string.substring(v.start,$e);/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(dt)&&(d.md_inside=!0)}return v.backUp(1),d.htmlState=b.startState(te),z(v,d,W)}if(_.xml&&le==="<"&&v.match(/^\/\w*?>/))return d.md_inside=!1,"tag";if(le==="*"||le==="_"){for(var Pe=1,_e=v.pos==1?" ":v.string.charAt(v.pos-2);Pe<3&&v.eat(le);)Pe++;var Ue=v.peek()||" ",et=!/\s/.test(Ue)&&(!w.test(Ue)||/\s/.test(_e)||w.test(_e)),we=!/\s/.test(_e)&&(!w.test(_e)||/\s/.test(Ue)||w.test(Ue)),Ie=null,E=null;if(Pe%2&&(!d.em&&et&&(le==="*"||!we||w.test(_e))?Ie=!0:d.em==le&&we&&(le==="*"||!et||w.test(Ue))&&(Ie=!1)),Pe>1&&(!d.strong&&et&&(le==="*"||!we||w.test(_e))?E=!0:d.strong==le&&we&&(le==="*"||!et||w.test(Ue))&&(E=!1)),E!=null||Ie!=null){_.highlightFormatting&&(d.formatting=Ie==null?"strong":E==null?"em":"strong em"),Ie===!0&&(d.em=le),E===!0&&(d.strong=le);var ve=P(d);return Ie===!1&&(d.em=!1),E===!1&&(d.strong=!1),ve}}else if(le===" "&&(v.eat("*")||v.eat("_"))){if(v.peek()===" ")return P(d);v.backUp(1)}if(_.strikethrough){if(le==="~"&&v.eatWhile(le)){if(d.strikethrough){_.highlightFormatting&&(d.formatting="strikethrough");var ve=P(d);return d.strikethrough=!1,ve}else if(v.match(/^[^\s]/,!1))return d.strikethrough=!0,_.highlightFormatting&&(d.formatting="strikethrough"),P(d)}else if(le===" "&&v.match("~~",!0)){if(v.peek()===" ")return P(d);v.backUp(2)}}if(_.emoji&&le===":"&&v.match(/^(?:[a-z_\d+][a-z_\d+-]*|\-[a-z_\d+][a-z_\d+-]*):/)){d.emoji=!0,_.highlightFormatting&&(d.formatting="emoji");var ee=P(d);return d.emoji=!1,ee}return le===" "&&(v.match(/^ +$/,!1)?d.trailingSpace++:d.trailingSpace&&(d.trailingSpaceNewLine=!0)),P(d)}function G(v,d){var fe=v.next();if(fe===">"){d.f=d.inline=F,_.highlightFormatting&&(d.formatting="link");var Te=P(d);return Te?Te+=" ":Te="",Te+k.linkInline}return v.match(/^[^>]+/,!0),k.linkInline}function c(v,d){if(v.eatSpace())return null;var fe=v.next();return fe==="("||fe==="["?(d.f=d.inline=C(fe==="("?")":"]"),_.highlightFormatting&&(d.formatting="link-string"),d.linkHref=!0,P(d)):"error"}var T={")":/^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,"]":/^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\]]|\\.)*\])*?(?=\])/};function C(v){return function(d,fe){var Te=d.next();if(Te===v){fe.f=fe.inline=F,_.highlightFormatting&&(fe.formatting="link-string");var le=P(fe);return fe.linkHref=!1,le}return d.match(T[v]),fe.linkHref=!0,P(fe)}}function g(v,d){return v.match(/^([^\]\\]|\\.)*\]:/,!1)?(d.f=y,v.next(),_.highlightFormatting&&(d.formatting="link"),d.linkText=!0,P(d)):N(v,d,F)}function y(v,d){if(v.match("]:",!0)){d.f=d.inline=j,_.highlightFormatting&&(d.formatting="link");var fe=P(d);return d.linkText=!1,fe}return v.match(/^([^\]\\]|\\.)+/,!0),k.linkText}function j(v,d){return v.eatSpace()?null:(v.match(/^[^\s]+/,!0),v.peek()===void 0?d.linkTitle=!0:v.match(/^(?:\s+(?:"(?:[^"\\]|\\.)+"|'(?:[^'\\]|\\.)+'|\((?:[^)\\]|\\.)+\)))?/,!0),d.f=d.inline=F,k.linkHref+" url")}var de={startState:function(){return{f:p,prevLine:{stream:null},thisLine:{stream:null},block:p,htmlState:null,indentation:0,inline:F,text:V,formatting:!1,linkText:!1,linkHref:!1,linkTitle:!1,code:0,em:!1,strong:!1,header:0,setext:0,hr:!1,taskList:!1,list:!1,listStack:[],quote:0,trailingSpace:0,trailingSpaceNewLine:!1,strikethrough:!1,emoji:!1,fencedEndRE:null}},copyState:function(v){return{f:v.f,prevLine:v.prevLine,thisLine:v.thisLine,block:v.block,htmlState:v.htmlState&&b.copyState(te,v.htmlState),indentation:v.indentation,localMode:v.localMode,localState:v.localMode?b.copyState(v.localMode,v.localState):null,inline:v.inline,text:v.text,formatting:!1,linkText:v.linkText,linkTitle:v.linkTitle,linkHref:v.linkHref,code:v.code,em:v.em,strong:v.strong,strikethrough:v.strikethrough,emoji:v.emoji,header:v.header,setext:v.setext,hr:v.hr,taskList:v.taskList,list:v.list,listStack:v.listStack.slice(0),quote:v.quote,indentedCode:v.indentedCode,trailingSpace:v.trailingSpace,trailingSpaceNewLine:v.trailingSpaceNewLine,md_inside:v.md_inside,fencedEndRE:v.fencedEndRE}},token:function(v,d){if(d.formatting=!1,v!=d.thisLine.stream){if(d.header=0,d.hr=!1,v.match(/^\s*$/,!0))return q(d),null;if(d.prevLine=d.thisLine,d.thisLine={stream:v},d.taskList=!1,d.trailingSpace=0,d.trailingSpaceNewLine=!1,!d.localState&&(d.f=d.block,d.f!=W)){var fe=v.match(/^\s*/,!0)[0].replace(/\t/g,M).length;if(d.indentation=fe,d.indentationDiff=null,fe>0)return null}}return d.f(v,d)},innerMode:function(v){return v.block==W?{state:v.htmlState,mode:te}:v.localState?{state:v.localState,mode:v.localMode}:{state:v,mode:de}},indent:function(v,d,fe){return v.block==W&&te.indent?te.indent(v.htmlState,d,fe):v.localState&&v.localMode.indent?v.localMode.indent(v.localState,d,fe):b.Pass},blankLine:q,getType:P,blockCommentStart:"",closeBrackets:"()[]{}''\"\"``",fold:"markdown"};return de},"xml"),b.defineMIME("text/markdown","markdown"),b.defineMIME("text/x-markdown","markdown")})})()),Da.exports}nf();var Na={exports:{}},Ea;function of(){return Ea||(Ea=1,(function(ct,xt){(function(b){b(mt())})(function(b){b.defineOption("placeholder","",function(I,Y,ne){var S=ne&&ne!=b.Init;if(Y&&!S)I.on("blur",oe),I.on("change",Q),I.on("swapDoc",Q),b.on(I.getInputField(),"compositionupdate",I.state.placeholderCompose=function(){te(I)}),Q(I);else if(!Y&&S){I.off("blur",oe),I.off("change",Q),I.off("swapDoc",Q),b.off(I.getInputField(),"compositionupdate",I.state.placeholderCompose),pe(I);var R=I.getWrapperElement();R.className=R.className.replace(" CodeMirror-empty","")}Y&&!I.hasFocus()&&oe(I)});function pe(I){I.state.placeholder&&(I.state.placeholder.parentNode.removeChild(I.state.placeholder),I.state.placeholder=null)}function _(I){pe(I);var Y=I.state.placeholder=document.createElement("pre");Y.style.cssText="height: 0; overflow: visible",Y.style.direction=I.getOption("direction"),Y.className="CodeMirror-placeholder CodeMirror-line-like";var ne=I.getOption("placeholder");typeof ne=="string"&&(ne=document.createTextNode(ne)),Y.appendChild(ne),I.display.lineSpace.insertBefore(Y,I.display.lineSpace.firstChild)}function te(I){setTimeout(function(){var Y=!1;if(I.lineCount()==1){var ne=I.getInputField();Y=ne.nodeName=="TEXTAREA"?!I.getLine(0).length:!/[^\u200b]/.test(ne.querySelector(".CodeMirror-line").textContent)}Y?_(I):pe(I)},20)}function oe(I){k(I)&&_(I)}function Q(I){var Y=I.getWrapperElement(),ne=k(I);Y.className=Y.className.replace(" CodeMirror-empty","")+(ne?" CodeMirror-empty":""),ne?_(I):pe(I)}function k(I){return I.lineCount()===1&&I.getLine(0)===""}})})()),Na.exports}of();var Oa={exports:{}},Pa;function lf(){return Pa||(Pa=1,(function(ct,xt){(function(b){b(mt())})(function(b){b.defineSimpleMode=function(S,R){b.defineMode(S,function(A){return b.simpleMode(A,R)})},b.simpleMode=function(S,R){pe(R,"start");var A={},$=R.meta||{},ue=!1;for(var O in R)if(O!=$&&R.hasOwnProperty(O))for(var w=A[O]=[],M=R[O],N=0;N2&&z.token&&typeof z.token!="string"){for(var p=2;p-1)return b.Pass;var O=A.indent.length-1,w=S[A.state];e:for(;;){for(var M=0;M",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function oe(S){return S&&S.bracketRegex||/[(){}[\]]/}function Q(S,R,A){var $=S.getLineHandle(R.line),ue=R.ch-1,O=A&&A.afterCursor;O==null&&(O=/(^| )cm-fat-cursor($| )/.test(S.getWrapperElement().className));var w=oe(A),M=!O&&ue>=0&&w.test($.text.charAt(ue))&&te[$.text.charAt(ue)]||w.test($.text.charAt(ue+1))&&te[$.text.charAt(++ue)];if(!M)return null;var N=M.charAt(1)==">"?1:-1;if(A&&A.strict&&N>0!=(ue==R.ch))return null;var z=S.getTokenTypeAt(_(R.line,ue+1)),X=k(S,_(R.line,ue+(N>0?1:0)),N,z,A);return X==null?null:{from:_(R.line,ue),to:X&&X.pos,match:X&&X.ch==M.charAt(0),forward:N>0}}function k(S,R,A,$,ue){for(var O=ue&&ue.maxScanLineLength||1e4,w=ue&&ue.maxScanLines||1e3,M=[],N=oe(ue),z=A>0?Math.min(R.line+w,S.lastLine()+1):Math.max(S.firstLine()-1,R.line-w),X=R.line;X!=z;X+=A){var q=S.getLine(X);if(q){var p=A>0?0:q.length-1,W=A>0?q.length:-1;if(!(q.length>O))for(X==R.line&&(p=R.ch-(A<0?1:0));p!=W;p+=A){var J=q.charAt(p);if(N.test(J)&&($===void 0||(S.getTokenTypeAt(_(X,p+1))||"")==($||""))){var P=te[J];if(P&&P.charAt(1)==">"==A>0)M.push(J);else if(M.length)M.pop();else return{pos:_(X,p),ch:J}}}}}return X-A==(A>0?S.lastLine():S.firstLine())?!1:null}function I(S,R,A){for(var $=S.state.matchBrackets.maxHighlightLineLength||1e3,ue=A&&A.highlightNonMatching,O=[],w=S.listSelections(),M=0;M`,triples:"",explode:"[]{}"},_=b.Pos;b.defineOption("autoCloseBrackets",!1,function(O,w,M){M&&M!=b.Init&&(O.removeKeyMap(oe),O.state.closeBrackets=null),w&&(Q(te(w,"pairs")),O.state.closeBrackets=w,O.addKeyMap(oe))});function te(O,w){return w=="pairs"&&typeof O=="string"?O:typeof O=="object"&&O[w]!=null?O[w]:pe[w]}var oe={Backspace:Y,Enter:ne};function Q(O){for(var w=0;w=0;z--){var q=N[z].head;O.replaceRange("",_(q.line,q.ch-1),_(q.line,q.ch+1),"+delete")}}function ne(O){var w=I(O),M=w&&te(w,"explode");if(!M||O.getOption("disableInput"))return b.Pass;for(var N=O.listSelections(),z=0;z0?{line:q.head.line,ch:q.head.ch+w}:{line:q.head.line-1};M.push({anchor:p,head:p})}O.setSelections(M,z)}function R(O){var w=b.cmpPos(O.anchor,O.head)>0;return{anchor:new _(O.anchor.line,O.anchor.ch+(w?-1:1)),head:new _(O.head.line,O.head.ch+(w?1:-1))}}function A(O,w){var M=I(O);if(!M||O.getOption("disableInput"))return b.Pass;var N=te(M,"pairs"),z=N.indexOf(w);if(z==-1)return b.Pass;for(var X=te(M,"closeBefore"),q=te(M,"triples"),p=N.charAt(z+1)==w,W=O.listSelections(),J=z%2==0,P,V=0;V=0&&O.getRange(G,_(G.line,G.ch+3))==w+w+w?c="skipThree":c="skip";else if(p&&G.ch>1&&q.indexOf(w)>=0&&O.getRange(_(G.line,G.ch-2),G)==w+w){if(G.ch>2&&/\bstring/.test(O.getTokenTypeAt(_(G.line,G.ch-2))))return b.Pass;c="addFour"}else if(p){var C=G.ch==0?" ":O.getRange(_(G.line,G.ch-1),G);if(!b.isWordChar(T)&&C!=w&&!b.isWordChar(C))c="both";else return b.Pass}else if(J&&(T.length===0||/\s/.test(T)||X.indexOf(T)>-1))c="both";else return b.Pass;if(!P)P=c;else if(P!=c)return b.Pass}var g=z%2?N.charAt(z-1):w,y=z%2?w:N.charAt(z+1);O.operation(function(){if(P=="skip")S(O,1);else if(P=="skipThree")S(O,3);else if(P=="surround"){for(var j=O.getSelections(),de=0;dep);W++){var J=w.getLine(q++);z=z==null?J:z+` -`+J}X=X*2,M.lastIndex=N.ch;var P=M.exec(z);if(P){var V=z.slice(0,P.index).split(` -`),F=P[0].split(` -`),G=N.line+V.length-1,c=V[V.length-1].length;return{from:pe(G,c),to:pe(G+F.length-1,F.length==1?c+F[0].length:F[F.length-1].length),match:P}}}}function I(w,M,N){for(var z,X=0;X<=w.length;){M.lastIndex=X;var q=M.exec(w);if(!q)break;var p=q.index+q[0].length;if(p>w.length-N)break;(!z||p>z.index+z[0].length)&&(z=q),X=q.index+1}return z}function Y(w,M,N){M=te(M,"g");for(var z=N.line,X=N.ch,q=w.firstLine();z>=q;z--,X=-1){var p=w.getLine(z),W=I(p,M,X<0?0:p.length-X);if(W)return{from:pe(z,W.index),to:pe(z,W.index+W[0].length),match:W}}}function ne(w,M,N){if(!oe(M))return Y(w,M,N);M=te(M,"gm");for(var z,X=1,q=w.getLine(N.line).length-N.ch,p=N.line,W=w.firstLine();p>=W;){for(var J=0;J=W;J++){var P=w.getLine(p--);z=z==null?P:P+` -`+z}X*=2;var V=I(z,M,q);if(V){var F=z.slice(0,V.index).split(` -`),G=V[0].split(` -`),c=p+F.length,T=F[F.length-1].length;return{from:pe(c,T),to:pe(c+G.length-1,G.length==1?T+G[0].length:G[G.length-1].length),match:V}}}}var S,R;String.prototype.normalize?(S=function(w){return w.normalize("NFD").toLowerCase()},R=function(w){return w.normalize("NFD")}):(S=function(w){return w.toLowerCase()},R=function(w){return w});function A(w,M,N,z){if(w.length==M.length)return N;for(var X=0,q=N+Math.max(0,w.length-M.length);;){if(X==q)return X;var p=X+q>>1,W=z(w.slice(0,p)).length;if(W==N)return p;W>N?q=p:X=p+1}}function $(w,M,N,z){if(!M.length)return null;var X=z?S:R,q=X(M).split(/\r|\n\r?/);e:for(var p=N.line,W=N.ch,J=w.lastLine()+1-q.length;p<=J;p++,W=0){var P=w.getLine(p).slice(W),V=X(P);if(q.length==1){var F=V.indexOf(q[0]);if(F==-1)continue e;var N=A(P,V,F,X)+W;return{from:pe(p,A(P,V,F,X)+W),to:pe(p,A(P,V,F+q[0].length,X)+W)}}else{var G=V.length-q[0].length;if(V.slice(G)!=q[0])continue e;for(var c=1;c=J;p--,W=-1){var P=w.getLine(p);W>-1&&(P=P.slice(0,W));var V=X(P);if(q.length==1){var F=V.lastIndexOf(q[0]);if(F==-1)continue e;return{from:pe(p,A(P,V,F,X)),to:pe(p,A(P,V,F+q[0].length,X))}}else{var G=q[q.length-1];if(V.slice(0,G.length)!=G)continue e;for(var c=1,N=p-q.length+1;c(this.doc.getLine(M.line)||"").length&&(M.ch=0,M.line++)),b.cmpPos(M,this.doc.clipPos(M))!=0))return this.atOccurrence=!1;var N=this.matches(w,M);if(this.afterEmptyMatch=N&&b.cmpPos(N.from,N.to)==0,N)return this.pos=N,this.atOccurrence=!0,this.pos.match||!0;var z=pe(w?this.doc.firstLine():this.doc.lastLine()+1,0);return this.pos={from:z,to:z},this.atOccurrence=!1},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(w,M){if(this.atOccurrence){var N=b.splitLines(w);this.doc.replaceRange(N,this.pos.from,this.pos.to,M),this.pos.to=pe(this.pos.from.line+N.length-1,N[N.length-1].length+(N.length==1?this.pos.from.ch:0))}}},b.defineExtension("getSearchCursor",function(w,M,N){return new O(this.doc,w,M,N)}),b.defineDocExtension("getSearchCursor",function(w,M,N){return new O(this,w,M,N)}),b.defineExtension("selectMatches",function(w,M){for(var N=[],z=this.getSearchCursor(w,this.getCursor("from"),M);z.findNext()&&!(b.cmpPos(z.to(),this.getCursor("to"))>0);)N.push({anchor:z.from(),head:z.to()});N.length&&this.setSelections(N,0)})})})()),Ha.exports}var qa={exports:{}},ja;function po(){return ja||(ja=1,(function(ct,xt){(function(b){b(mt())})(function(b){function pe(te,oe,Q){var k=te.getWrapperElement(),I;return I=k.appendChild(document.createElement("div")),Q?I.className="CodeMirror-dialog CodeMirror-dialog-bottom":I.className="CodeMirror-dialog CodeMirror-dialog-top",typeof oe=="string"?I.innerHTML=oe:I.appendChild(oe),b.addClass(k,"dialog-opened"),I}function _(te,oe){te.state.currentNotificationClose&&te.state.currentNotificationClose(),te.state.currentNotificationClose=oe}b.defineExtension("openDialog",function(te,oe,Q){Q||(Q={}),_(this,null);var k=pe(this,te,Q.bottom),I=!1,Y=this;function ne(A){if(typeof A=="string")S.value=A;else{if(I)return;I=!0,b.rmClass(k.parentNode,"dialog-opened"),k.parentNode.removeChild(k),Y.focus(),Q.onClose&&Q.onClose(k)}}var S=k.getElementsByTagName("input")[0],R;return S?(S.focus(),Q.value&&(S.value=Q.value,Q.selectValueOnOpen!==!1&&S.select()),Q.onInput&&b.on(S,"input",function(A){Q.onInput(A,S.value,ne)}),Q.onKeyUp&&b.on(S,"keyup",function(A){Q.onKeyUp(A,S.value,ne)}),b.on(S,"keydown",function(A){Q&&Q.onKeyDown&&Q.onKeyDown(A,S.value,ne)||((A.keyCode==27||Q.closeOnEnter!==!1&&A.keyCode==13)&&(S.blur(),b.e_stop(A),ne()),A.keyCode==13&&oe(S.value,A))}),Q.closeOnBlur!==!1&&b.on(k,"focusout",function(A){A.relatedTarget!==null&&ne()})):(R=k.getElementsByTagName("button")[0])&&(b.on(R,"click",function(){ne(),Y.focus()}),Q.closeOnBlur!==!1&&b.on(R,"blur",ne),R.focus()),ne}),b.defineExtension("openConfirm",function(te,oe,Q){_(this,null);var k=pe(this,te,Q&&Q.bottom),I=k.getElementsByTagName("button"),Y=!1,ne=this,S=1;function R(){Y||(Y=!0,b.rmClass(k.parentNode,"dialog-opened"),k.parentNode.removeChild(k),ne.focus())}I[0].focus();for(var A=0;Ap.cursorCoords(y,"window").top&&((G=j).style.opacity=.4)}))};k(p,w(p),F,c,function(T,C){var g=b.keyName(T),y=p.getOption("extraKeys"),j=y&&y[g]||b.keyMap[p.getOption("keyMap")][g];j=="findNext"||j=="findPrev"||j=="findPersistentNext"||j=="findPersistentPrev"?(b.e_stop(T),R(p,te(p),C),p.execCommand(j)):(j=="find"||j=="findPersistent")&&(b.e_stop(T),c(C,T))}),P&&F&&(R(p,V,F),$(p,W))}else I(p,w(p),"Search for:",F,function(T){T&&!V.query&&p.operation(function(){R(p,V,T),V.posFrom=V.posTo=p.getCursor(),$(p,W)})})}function $(p,W,J){p.operation(function(){var P=te(p),V=Q(p,P.query,W?P.posFrom:P.posTo);!V.find(W)&&(V=Q(p,P.query,W?b.Pos(p.lastLine()):b.Pos(p.firstLine(),0)),!V.find(W))||(p.setSelection(V.from(),V.to()),p.scrollIntoView({from:V.from(),to:V.to()},20),P.posFrom=V.from(),P.posTo=V.to(),J&&J(V.from(),V.to()))})}function ue(p){p.operation(function(){var W=te(p);W.lastQuery=W.query,W.query&&(W.query=W.queryText=null,p.removeOverlay(W.overlay),W.annotate&&(W.annotate.clear(),W.annotate=null))})}function O(p,W){var J=p?document.createElement(p):document.createDocumentFragment();for(var P in W)J[P]=W[P];for(var V=2;V '+oe.phrase("(Use line:column or scroll% syntax)")+""}function te(oe,Q){var k=Number(Q);return/^[-+]/.test(Q)?oe.getCursor().line+k:k-1}b.commands.jumpToLine=function(oe){var Q=oe.getCursor();pe(oe,_(oe),oe.phrase("Jump to line:"),Q.line+1+":"+Q.ch,function(k){if(k){var I;if(I=/^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(k))oe.setCursor(te(oe,I[1]),Number(I[2]));else if(I=/^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(k)){var Y=Math.round(oe.lineCount()*Number(I[1])/100);/^[-+]/.test(I[1])&&(Y=Q.line+Y+1),oe.setCursor(Y-1,Q.ch)}else(I=/^\s*\:?\s*([\+\-]?\d+)\s*/.exec(k))&&oe.setCursor(te(oe,I[1]),Q.ch)}})},b.keyMap.default["Alt-G"]="jumpToLine"})})()),Ua.exports}ff();po();export{df as default}; diff --git a/frontend/playwright-report/trace/assets/defaultSettingsView-GTWI-W_B.js b/frontend/playwright-report/trace/assets/defaultSettingsView-GTWI-W_B.js deleted file mode 100644 index 3001229..0000000 --- a/frontend/playwright-report/trace/assets/defaultSettingsView-GTWI-W_B.js +++ /dev/null @@ -1,262 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./codeMirrorModule-DS0FLvoc.js","../codeMirrorModule.DYBRYzYX.css"])))=>i.map(i=>d[i]); -(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const o of l)if(o.type==="childList")for(const u of o.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&r(u)}).observe(document,{childList:!0,subtree:!0});function i(l){const o={};return l.integrity&&(o.integrity=l.integrity),l.referrerPolicy&&(o.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?o.credentials="include":l.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(l){if(l.ep)return;l.ep=!0;const o=i(l);fetch(l.href,o)}})();function ex(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}var Wf={exports:{}},Ma={};/** - * @license React - * react-jsx-runtime.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var qy;function tx(){if(qy)return Ma;qy=1;var n=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function i(r,l,o){var u=null;if(o!==void 0&&(u=""+o),l.key!==void 0&&(u=""+l.key),"key"in l){o={};for(var f in l)f!=="key"&&(o[f]=l[f])}else o=l;return l=o.ref,{$$typeof:n,type:r,key:u,ref:l!==void 0?l:null,props:o}}return Ma.Fragment=e,Ma.jsx=i,Ma.jsxs=i,Ma}var $y;function nx(){return $y||($y=1,Wf.exports=tx()),Wf.exports}var v=nx(),eh={exports:{}},ce={};/** - * @license React - * react.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Iy;function ix(){if(Iy)return ce;Iy=1;var n=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),i=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),l=Symbol.for("react.profiler"),o=Symbol.for("react.consumer"),u=Symbol.for("react.context"),f=Symbol.for("react.forward_ref"),d=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),b=Symbol.for("react.lazy"),m=Symbol.for("react.activity"),S=Symbol.iterator;function w(M){return M===null||typeof M!="object"?null:(M=S&&M[S]||M["@@iterator"],typeof M=="function"?M:null)}var T={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},x=Object.assign,_={};function A(M,Y,Z){this.props=M,this.context=Y,this.refs=_,this.updater=Z||T}A.prototype.isReactComponent={},A.prototype.setState=function(M,Y){if(typeof M!="object"&&typeof M!="function"&&M!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,M,Y,"setState")},A.prototype.forceUpdate=function(M){this.updater.enqueueForceUpdate(this,M,"forceUpdate")};function N(){}N.prototype=A.prototype;function $(M,Y,Z){this.props=M,this.context=Y,this.refs=_,this.updater=Z||T}var G=$.prototype=new N;G.constructor=$,x(G,A.prototype),G.isPureReactComponent=!0;var X=Array.isArray;function U(){}var L={H:null,A:null,T:null,S:null},B=Object.prototype.hasOwnProperty;function O(M,Y,Z){var P=Z.ref;return{$$typeof:n,type:M,key:Y,ref:P!==void 0?P:null,props:Z}}function ne(M,Y){return O(M.type,Y,M.props)}function te(M){return typeof M=="object"&&M!==null&&M.$$typeof===n}function V(M){var Y={"=":"=0",":":"=2"};return"$"+M.replace(/[=:]/g,function(Z){return Y[Z]})}var W=/\/+/g;function ge(M,Y){return typeof M=="object"&&M!==null&&M.key!=null?V(""+M.key):Y.toString(36)}function Ue(M){switch(M.status){case"fulfilled":return M.value;case"rejected":throw M.reason;default:switch(typeof M.status=="string"?M.then(U,U):(M.status="pending",M.then(function(Y){M.status==="pending"&&(M.status="fulfilled",M.value=Y)},function(Y){M.status==="pending"&&(M.status="rejected",M.reason=Y)})),M.status){case"fulfilled":return M.value;case"rejected":throw M.reason}}throw M}function I(M,Y,Z,P,oe){var he=typeof M;(he==="undefined"||he==="boolean")&&(M=null);var be=!1;if(M===null)be=!0;else switch(he){case"bigint":case"string":case"number":be=!0;break;case"object":switch(M.$$typeof){case n:case e:be=!0;break;case b:return be=M._init,I(be(M._payload),Y,Z,P,oe)}}if(be)return oe=oe(M),be=P===""?"."+ge(M,0):P,X(oe)?(Z="",be!=null&&(Z=be.replace(W,"$&/")+"/"),I(oe,Y,Z,"",function(Et){return Et})):oe!=null&&(te(oe)&&(oe=ne(oe,Z+(oe.key==null||M&&M.key===oe.key?"":(""+oe.key).replace(W,"$&/")+"/")+be)),Y.push(oe)),1;be=0;var rt=P===""?".":P+":";if(X(M))for(var ke=0;ke{let u=!1;return n().then(f=>{u||o(f)}),()=>{u=!0}},e),l}function ms(){const n=vt.useRef(null),[e]=xh(n);return[e,n]}function xh(n){const[e,i]=vt.useState(new DOMRect(0,0,10,10)),r=vt.useCallback(()=>{const l=n==null?void 0:n.current;l&&i(l.getBoundingClientRect())},[n]);return vt.useLayoutEffect(()=>{const l=n==null?void 0:n.current;if(!l)return;r();const o=new ResizeObserver(r);return o.observe(l),window.addEventListener("resize",r),()=>{o.disconnect(),window.removeEventListener("resize",r)}},[r,n]),[e,r]}function Zb(n,e,i,r,l){let o=0,u=n.length;for(;o>1;i(e,n[f])>=0?o=f+1:u=f}return u}function Gy(n){const e=document.createElement("textarea");e.style.position="absolute",e.style.zIndex="-1000",e.value=n,document.body.appendChild(e),e.select(),document.execCommand("copy"),e.remove()}function pn(n,e){n&&(e=us.getObject(n,e));const[i,r]=vt.useState(e),l=vt.useCallback(o=>{n?us.setObject(n,o):r(o)},[n,r]);return vt.useEffect(()=>{if(n){const o=()=>r(us.getObject(n,e));return us.onChangeEmitter.addEventListener(n,o),()=>us.onChangeEmitter.removeEventListener(n,o)}},[e,n]),[i,l]}const _h=new Map,Wb=new Map;let tc;function rr(n,e){const[i,r]=vt.useState();Wb.set(n,{setter:r,defaultValue:e});const l=vt.useCallback(o=>{const u=_h.get(tc||"default")||{};u[n]=o,_h.set(tc||"default",u),r(o)},[n]);return[i,l]}function sx(n){if(tc===n)return;tc=n;const e=_h.get(n)||{};for(const[i,r]of Wb.entries())r.setter(e[i]||r.defaultValue)}class rx{constructor(){this.onChangeEmitter=new EventTarget}getString(e,i){return localStorage[e]||i}setString(e,i){var r;localStorage[e]=i,this.onChangeEmitter.dispatchEvent(new Event(e)),(r=window.saveSettings)==null||r.call(window)}getObject(e,i){if(!localStorage[e])return i;try{return JSON.parse(localStorage[e])}catch{return i}}setObject(e,i){var r;localStorage[e]=JSON.stringify(i),this.onChangeEmitter.dispatchEvent(new Event(e)),(r=window.saveSettings)==null||r.call(window)}}const us=new rx;function st(...n){return n.filter(Boolean).join(" ")}function e0(n){n&&(n!=null&&n.scrollIntoViewIfNeeded?n.scrollIntoViewIfNeeded(!1):n==null||n.scrollIntoView())}const Ky="\\u0000-\\u0020\\u007f-\\u009f",t0=new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|www\\.)[^\\s"+Ky+'"]{2,}[^\\s'+Ky+`"')}\\],:;.!?]`,"ug");function ax(){const[n,e]=vt.useState(!1),i=vt.useCallback(()=>{const r=[];return e(l=>(r.push(setTimeout(()=>e(!1),1e3)),l?(r.push(setTimeout(()=>e(!0),50)),!1):!0)),()=>r.forEach(clearTimeout)},[e]);return[n,i]}const lx="system",n0="theme",ox=[{label:"Dark mode",value:"dark-mode"},{label:"Light mode",value:"light-mode"},{label:"System",value:"system"}],i0=window.matchMedia("(prefers-color-scheme: dark)");function m2(){document.playwrightThemeInitialized||(document.playwrightThemeInitialized=!0,document.defaultView.addEventListener("focus",n=>{n.target.document.nodeType===Node.DOCUMENT_NODE&&document.body.classList.remove("inactive")},!1),document.defaultView.addEventListener("blur",n=>{document.body.classList.add("inactive")},!1),Eh(Th()),i0.addEventListener("change",()=>{Eh(Th())}))}const Fh=new Set;function Eh(n){const e=cx(),i=n==="system"?i0.matches?"dark-mode":"light-mode":n;if(e!==i){e&&document.documentElement.classList.remove(e),document.documentElement.classList.add(i);for(const r of Fh)r(i)}}function y2(n){Fh.add(n)}function b2(n){Fh.delete(n)}function Th(){return us.getString(n0,lx)}function cx(){return document.documentElement.classList.contains("dark-mode")?"dark-mode":document.documentElement.classList.contains("light-mode")?"light-mode":null}function ux(){const[n,e]=vt.useState(Th());return vt.useEffect(()=>{us.setString(n0,n),Eh(n)},[n]),[n,e]}var th={exports:{}},Oa={},nh={exports:{}},ih={};/** - * @license React - * scheduler.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Xy;function fx(){return Xy||(Xy=1,(function(n){function e(I,J){var re=I.length;I.push(J);e:for(;0>>1,_e=I[xe];if(0>>1;xel(Z,re))P<_e&&0>l(oe,Z)?(I[xe]=oe,I[P]=re,xe=P):(I[xe]=Z,I[Y]=re,xe=Y);else if(P<_e&&0>l(oe,re))I[xe]=oe,I[P]=re,xe=P;else break e}}return J}function l(I,J){var re=I.sortIndex-J.sortIndex;return re!==0?re:I.id-J.id}if(n.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;n.unstable_now=function(){return o.now()}}else{var u=Date,f=u.now();n.unstable_now=function(){return u.now()-f}}var d=[],g=[],b=1,m=null,S=3,w=!1,T=!1,x=!1,_=!1,A=typeof setTimeout=="function"?setTimeout:null,N=typeof clearTimeout=="function"?clearTimeout:null,$=typeof setImmediate<"u"?setImmediate:null;function G(I){for(var J=i(g);J!==null;){if(J.callback===null)r(g);else if(J.startTime<=I)r(g),J.sortIndex=J.expirationTime,e(d,J);else break;J=i(g)}}function X(I){if(x=!1,G(I),!T)if(i(d)!==null)T=!0,U||(U=!0,V());else{var J=i(g);J!==null&&Ue(X,J.startTime-I)}}var U=!1,L=-1,B=5,O=-1;function ne(){return _?!0:!(n.unstable_now()-OI&&ne());){var xe=m.callback;if(typeof xe=="function"){m.callback=null,S=m.priorityLevel;var _e=xe(m.expirationTime<=I);if(I=n.unstable_now(),typeof _e=="function"){m.callback=_e,G(I),J=!0;break t}m===i(d)&&r(d),G(I)}else r(d);m=i(d)}if(m!==null)J=!0;else{var M=i(g);M!==null&&Ue(X,M.startTime-I),J=!1}}break e}finally{m=null,S=re,w=!1}J=void 0}}finally{J?V():U=!1}}}var V;if(typeof $=="function")V=function(){$(te)};else if(typeof MessageChannel<"u"){var W=new MessageChannel,ge=W.port2;W.port1.onmessage=te,V=function(){ge.postMessage(null)}}else V=function(){A(te,0)};function Ue(I,J){L=A(function(){I(n.unstable_now())},J)}n.unstable_IdlePriority=5,n.unstable_ImmediatePriority=1,n.unstable_LowPriority=4,n.unstable_NormalPriority=3,n.unstable_Profiling=null,n.unstable_UserBlockingPriority=2,n.unstable_cancelCallback=function(I){I.callback=null},n.unstable_forceFrameRate=function(I){0>I||125xe?(I.sortIndex=re,e(g,I),i(d)===null&&I===i(g)&&(x?(N(L),L=-1):x=!0,Ue(X,re-xe))):(I.sortIndex=_e,e(d,I),T||w||(T=!0,U||(U=!0,V()))),I},n.unstable_shouldYield=ne,n.unstable_wrapCallback=function(I){var J=S;return function(){var re=S;S=J;try{return I.apply(this,arguments)}finally{S=re}}}})(ih)),ih}var Yy;function hx(){return Yy||(Yy=1,nh.exports=fx()),nh.exports}var sh={exports:{}},wt={};/** - * @license React - * react-dom.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Fy;function dx(){if(Fy)return wt;Fy=1;var n=Xh();function e(d){var g="https://react.dev/errors/"+d;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}return n(),sh.exports=dx(),sh.exports}/** - * @license React - * react-dom-client.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Py;function gx(){if(Py)return Oa;Py=1;var n=hx(),e=Xh(),i=px();function r(t){var s="https://react.dev/errors/"+t;if(1_e||(t.current=xe[_e],xe[_e]=null,_e--)}function Z(t,s){_e++,xe[_e]=t.current,t.current=s}var P=M(null),oe=M(null),he=M(null),be=M(null);function rt(t,s){switch(Z(he,s),Z(oe,t),Z(P,null),s.nodeType){case 9:case 11:t=(t=s.documentElement)&&(t=t.namespaceURI)?cy(t):0;break;default:if(t=s.tagName,s=s.namespaceURI)s=cy(s),t=uy(s,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}Y(P),Z(P,t)}function ke(){Y(P),Y(oe),Y(he)}function Et(t){t.memoizedState!==null&&Z(be,t);var s=P.current,a=uy(s,t.type);s!==a&&(Z(oe,t),Z(P,a))}function fe(t){oe.current===t&&(Y(P),Y(oe)),be.current===t&&(Y(be),Aa._currentValue=re)}var Ne,qe;function Ee(t){if(Ne===void 0)try{throw Error()}catch(a){var s=a.stack.trim().match(/\n( *(at )?)/);Ne=s&&s[1]||"",qe=-1)":-1h||C[c]!==z[h]){var K=` -`+C[c].replace(" at new "," at ");return t.displayName&&K.includes("")&&(K=K.replace("",t.displayName)),K}while(1<=c&&0<=h);break}}}finally{Gt=!1,Error.prepareStackTrace=a}return(a=t?t.displayName||t.name:"")?Ee(a):""}function en(t,s){switch(t.tag){case 26:case 27:case 5:return Ee(t.type);case 16:return Ee("Lazy");case 13:return t.child!==s&&s!==null?Ee("Suspense Fallback"):Ee("Suspense");case 19:return Ee("SuspenseList");case 0:case 15:return Wt(t.type,!1);case 11:return Wt(t.type.render,!1);case 1:return Wt(t.type,!0);case 31:return Ee("Activity");default:return""}}function qi(t){try{var s="",a=null;do s+=en(t,a),a=t,t=t.return;while(t);return s}catch(c){return` -Error generating stack: `+c.message+` -`+c.stack}}var Ss=Object.prototype.hasOwnProperty,ri=n.unstable_scheduleCallback,Ur=n.unstable_cancelCallback,ai=n.unstable_shouldYield,zc=n.unstable_requestPaint,Tt=n.unstable_now,Uc=n.unstable_getCurrentPriorityLevel,hl=n.unstable_ImmediatePriority,Hr=n.unstable_UserBlockingPriority,li=n.unstable_NormalPriority,Hc=n.unstable_LowPriority,dl=n.unstable_IdlePriority,Bc=n.log,$i=n.unstable_setDisableYieldValue,En=null,At=null;function Tn(t){if(typeof Bc=="function"&&$i(t),At&&typeof At.setStrictMode=="function")try{At.setStrictMode(En,t)}catch{}}var Ct=Math.clz32?Math.clz32:Ii,pl=Math.log,ae=Math.LN2;function Ii(t){return t>>>=0,t===0?32:31-(pl(t)/ae|0)|0}var tn=256,gl=262144,ml=4194304;function Vi(t){var s=t&42;if(s!==0)return s;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function yl(t,s,a){var c=t.pendingLanes;if(c===0)return 0;var h=0,p=t.suspendedLanes,y=t.pingedLanes;t=t.warmLanes;var E=c&134217727;return E!==0?(c=E&~p,c!==0?h=Vi(c):(y&=E,y!==0?h=Vi(y):a||(a=E&~t,a!==0&&(h=Vi(a))))):(E=c&~p,E!==0?h=Vi(E):y!==0?h=Vi(y):a||(a=c&~t,a!==0&&(h=Vi(a)))),h===0?0:s!==0&&s!==h&&(s&p)===0&&(p=h&-h,a=s&-s,p>=a||p===32&&(a&4194048)!==0)?s:h}function Br(t,s){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&s)===0}function $S(t,s){switch(t){case 1:case 2:case 4:case 8:case 64:return s+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return s+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Gd(){var t=ml;return ml<<=1,(ml&62914560)===0&&(ml=4194304),t}function qc(t){for(var s=[],a=0;31>a;a++)s.push(t);return s}function qr(t,s){t.pendingLanes|=s,s!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function IS(t,s,a,c,h,p){var y=t.pendingLanes;t.pendingLanes=a,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=a,t.entangledLanes&=a,t.errorRecoveryDisabledLanes&=a,t.shellSuspendCounter=0;var E=t.entanglements,C=t.expirationTimes,z=t.hiddenUpdates;for(a=y&~a;0"u")return null;try{return t.activeElement||t.body}catch{return t.body}}var FS=/[\n"\\]/g;function sn(t){return t.replace(FS,function(s){return"\\"+s.charCodeAt(0).toString(16)+" "})}function Xc(t,s,a,c,h,p,y,E){t.name="",y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"?t.type=y:t.removeAttribute("type"),s!=null?y==="number"?(s===0&&t.value===""||t.value!=s)&&(t.value=""+nn(s)):t.value!==""+nn(s)&&(t.value=""+nn(s)):y!=="submit"&&y!=="reset"||t.removeAttribute("value"),s!=null?Yc(t,y,nn(s)):a!=null?Yc(t,y,nn(a)):c!=null&&t.removeAttribute("value"),h==null&&p!=null&&(t.defaultChecked=!!p),h!=null&&(t.checked=h&&typeof h!="function"&&typeof h!="symbol"),E!=null&&typeof E!="function"&&typeof E!="symbol"&&typeof E!="boolean"?t.name=""+nn(E):t.removeAttribute("name")}function ip(t,s,a,c,h,p,y,E){if(p!=null&&typeof p!="function"&&typeof p!="symbol"&&typeof p!="boolean"&&(t.type=p),s!=null||a!=null){if(!(p!=="submit"&&p!=="reset"||s!=null)){Kc(t);return}a=a!=null?""+nn(a):"",s=s!=null?""+nn(s):a,E||s===t.value||(t.value=s),t.defaultValue=s}c=c??h,c=typeof c!="function"&&typeof c!="symbol"&&!!c,t.checked=E?t.checked:!!c,t.defaultChecked=!!c,y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"&&(t.name=y),Kc(t)}function Yc(t,s,a){s==="number"&&Sl(t.ownerDocument)===t||t.defaultValue===""+a||(t.defaultValue=""+a)}function As(t,s,a,c){if(t=t.options,s){s={};for(var h=0;h"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Zc=!1;if(zn)try{var Gr={};Object.defineProperty(Gr,"passive",{get:function(){Zc=!0}}),window.addEventListener("test",Gr,Gr),window.removeEventListener("test",Gr,Gr)}catch{Zc=!1}var ci=null,Wc=null,xl=null;function up(){if(xl)return xl;var t,s=Wc,a=s.length,c,h="value"in ci?ci.value:ci.textContent,p=h.length;for(t=0;t=Yr),mp=" ",yp=!1;function bp(t,s){switch(t){case"keyup":return x1.indexOf(s.keyCode)!==-1;case"keydown":return s.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function vp(t){return t=t.detail,typeof t=="object"&&"data"in t?t.data:null}var Ms=!1;function E1(t,s){switch(t){case"compositionend":return vp(s);case"keypress":return s.which!==32?null:(yp=!0,mp);case"textInput":return t=s.data,t===mp&&yp?null:t;default:return null}}function T1(t,s){if(Ms)return t==="compositionend"||!su&&bp(t,s)?(t=up(),xl=Wc=ci=null,Ms=!1,t):null;switch(t){case"paste":return null;case"keypress":if(!(s.ctrlKey||s.altKey||s.metaKey)||s.ctrlKey&&s.altKey){if(s.char&&1=s)return{node:a,offset:s-t};t=c}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=Cp(a)}}function kp(t,s){return t&&s?t===s?!0:t&&t.nodeType===3?!1:s&&s.nodeType===3?kp(t,s.parentNode):"contains"in t?t.contains(s):t.compareDocumentPosition?!!(t.compareDocumentPosition(s)&16):!1:!1}function Mp(t){t=t!=null&&t.ownerDocument!=null&&t.ownerDocument.defaultView!=null?t.ownerDocument.defaultView:window;for(var s=Sl(t.document);s instanceof t.HTMLIFrameElement;){try{var a=typeof s.contentWindow.location.href=="string"}catch{a=!1}if(a)t=s.contentWindow;else break;s=Sl(t.document)}return s}function lu(t){var s=t&&t.nodeName&&t.nodeName.toLowerCase();return s&&(s==="input"&&(t.type==="text"||t.type==="search"||t.type==="tel"||t.type==="url"||t.type==="password")||s==="textarea"||t.contentEditable==="true")}var L1=zn&&"documentMode"in document&&11>=document.documentMode,Os=null,ou=null,Jr=null,cu=!1;function Op(t,s,a){var c=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;cu||Os==null||Os!==Sl(c)||(c=Os,"selectionStart"in c&&lu(c)?c={start:c.selectionStart,end:c.selectionEnd}:(c=(c.ownerDocument&&c.ownerDocument.defaultView||window).getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset}),Jr&&Pr(Jr,c)||(Jr=c,c=mo(ou,"onSelect"),0>=y,h-=y,An=1<<32-Ct(s)+h|a<pe?(Se=ie,ie=null):Se=ie.sibling;var Ae=H(j,ie,D[pe],F);if(Ae===null){ie===null&&(ie=Se);break}t&&ie&&Ae.alternate===null&&s(j,ie),k=p(Ae,k,pe),Te===null?se=Ae:Te.sibling=Ae,Te=Ae,ie=Se}if(pe===D.length)return a(j,ie),we&&Hn(j,pe),se;if(ie===null){for(;pepe?(Se=ie,ie=null):Se=ie.sibling;var Oi=H(j,ie,Ae.value,F);if(Oi===null){ie===null&&(ie=Se);break}t&&ie&&Oi.alternate===null&&s(j,ie),k=p(Oi,k,pe),Te===null?se=Oi:Te.sibling=Oi,Te=Oi,ie=Se}if(Ae.done)return a(j,ie),we&&Hn(j,pe),se;if(ie===null){for(;!Ae.done;pe++,Ae=D.next())Ae=Q(j,Ae.value,F),Ae!==null&&(k=p(Ae,k,pe),Te===null?se=Ae:Te.sibling=Ae,Te=Ae);return we&&Hn(j,pe),se}for(ie=c(ie);!Ae.done;pe++,Ae=D.next())Ae=q(ie,j,pe,Ae.value,F),Ae!==null&&(t&&Ae.alternate!==null&&ie.delete(Ae.key===null?pe:Ae.key),k=p(Ae,k,pe),Te===null?se=Ae:Te.sibling=Ae,Te=Ae);return t&&ie.forEach(function(Ww){return s(j,Ww)}),we&&Hn(j,pe),se}function Re(j,k,D,F){if(typeof D=="object"&&D!==null&&D.type===x&&D.key===null&&(D=D.props.children),typeof D=="object"&&D!==null){switch(D.$$typeof){case w:e:{for(var se=D.key;k!==null;){if(k.key===se){if(se=D.type,se===x){if(k.tag===7){a(j,k.sibling),F=h(k,D.props.children),F.return=j,j=F;break e}}else if(k.elementType===se||typeof se=="object"&&se!==null&&se.$$typeof===B&&es(se)===k.type){a(j,k.sibling),F=h(k,D.props),ia(F,D),F.return=j,j=F;break e}a(j,k);break}else s(j,k);k=k.sibling}D.type===x?(F=Qi(D.props.children,j.mode,F,D.key),F.return=j,j=F):(F=jl(D.type,D.key,D.props,null,j.mode,F),ia(F,D),F.return=j,j=F)}return y(j);case T:e:{for(se=D.key;k!==null;){if(k.key===se)if(k.tag===4&&k.stateNode.containerInfo===D.containerInfo&&k.stateNode.implementation===D.implementation){a(j,k.sibling),F=h(k,D.children||[]),F.return=j,j=F;break e}else{a(j,k);break}else s(j,k);k=k.sibling}F=mu(D,j.mode,F),F.return=j,j=F}return y(j);case B:return D=es(D),Re(j,k,D,F)}if(Ue(D))return ee(j,k,D,F);if(V(D)){if(se=V(D),typeof se!="function")throw Error(r(150));return D=se.call(D),le(j,k,D,F)}if(typeof D.then=="function")return Re(j,k,Bl(D),F);if(D.$$typeof===$)return Re(j,k,Dl(j,D),F);ql(j,D)}return typeof D=="string"&&D!==""||typeof D=="number"||typeof D=="bigint"?(D=""+D,k!==null&&k.tag===6?(a(j,k.sibling),F=h(k,D),F.return=j,j=F):(a(j,k),F=gu(D,j.mode,F),F.return=j,j=F),y(j)):a(j,k)}return function(j,k,D,F){try{na=0;var se=Re(j,k,D,F);return Is=null,se}catch(ie){if(ie===$s||ie===Ul)throw ie;var Te=Xt(29,ie,null,j.mode);return Te.lanes=F,Te.return=j,Te}finally{}}}var ns=eg(!0),tg=eg(!1),pi=!1;function Nu(t){t.updateQueue={baseState:t.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function ku(t,s){t=t.updateQueue,s.updateQueue===t&&(s.updateQueue={baseState:t.baseState,firstBaseUpdate:t.firstBaseUpdate,lastBaseUpdate:t.lastBaseUpdate,shared:t.shared,callbacks:null})}function gi(t){return{lane:t,tag:0,payload:null,callback:null,next:null}}function mi(t,s,a){var c=t.updateQueue;if(c===null)return null;if(c=c.shared,(Ce&2)!==0){var h=c.pending;return h===null?s.next=s:(s.next=h.next,h.next=s),c.pending=s,s=Ol(t),Hp(t,null,a),s}return Ml(t,c,s,a),Ol(t)}function sa(t,s,a){if(s=s.updateQueue,s!==null&&(s=s.shared,(a&4194048)!==0)){var c=s.lanes;c&=t.pendingLanes,a|=c,s.lanes=a,Xd(t,a)}}function Mu(t,s){var a=t.updateQueue,c=t.alternate;if(c!==null&&(c=c.updateQueue,a===c)){var h=null,p=null;if(a=a.firstBaseUpdate,a!==null){do{var y={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};p===null?h=p=y:p=p.next=y,a=a.next}while(a!==null);p===null?h=p=s:p=p.next=s}else h=p=s;a={baseState:c.baseState,firstBaseUpdate:h,lastBaseUpdate:p,shared:c.shared,callbacks:c.callbacks},t.updateQueue=a;return}t=a.lastBaseUpdate,t===null?a.firstBaseUpdate=s:t.next=s,a.lastBaseUpdate=s}var Ou=!1;function ra(){if(Ou){var t=qs;if(t!==null)throw t}}function aa(t,s,a,c){Ou=!1;var h=t.updateQueue;pi=!1;var p=h.firstBaseUpdate,y=h.lastBaseUpdate,E=h.shared.pending;if(E!==null){h.shared.pending=null;var C=E,z=C.next;C.next=null,y===null?p=z:y.next=z,y=C;var K=t.alternate;K!==null&&(K=K.updateQueue,E=K.lastBaseUpdate,E!==y&&(E===null?K.firstBaseUpdate=z:E.next=z,K.lastBaseUpdate=C))}if(p!==null){var Q=h.baseState;y=0,K=z=C=null,E=p;do{var H=E.lane&-536870913,q=H!==E.lane;if(q?(ve&H)===H:(c&H)===H){H!==0&&H===Bs&&(Ou=!0),K!==null&&(K=K.next={lane:0,tag:E.tag,payload:E.payload,callback:null,next:null});e:{var ee=t,le=E;H=s;var Re=a;switch(le.tag){case 1:if(ee=le.payload,typeof ee=="function"){Q=ee.call(Re,Q,H);break e}Q=ee;break e;case 3:ee.flags=ee.flags&-65537|128;case 0:if(ee=le.payload,H=typeof ee=="function"?ee.call(Re,Q,H):ee,H==null)break e;Q=m({},Q,H);break e;case 2:pi=!0}}H=E.callback,H!==null&&(t.flags|=64,q&&(t.flags|=8192),q=h.callbacks,q===null?h.callbacks=[H]:q.push(H))}else q={lane:H,tag:E.tag,payload:E.payload,callback:E.callback,next:null},K===null?(z=K=q,C=Q):K=K.next=q,y|=H;if(E=E.next,E===null){if(E=h.shared.pending,E===null)break;q=E,E=q.next,q.next=null,h.lastBaseUpdate=q,h.shared.pending=null}}while(!0);K===null&&(C=Q),h.baseState=C,h.firstBaseUpdate=z,h.lastBaseUpdate=K,p===null&&(h.shared.lanes=0),wi|=y,t.lanes=y,t.memoizedState=Q}}function ng(t,s){if(typeof t!="function")throw Error(r(191,t));t.call(s)}function ig(t,s){var a=t.callbacks;if(a!==null)for(t.callbacks=null,t=0;tp?p:8;var y=I.T,E={};I.T=E,Pu(t,!1,s,a);try{var C=h(),z=I.S;if(z!==null&&z(E,C),C!==null&&typeof C=="object"&&typeof C.then=="function"){var K=I1(C,c);ca(t,s,K,Jt(t))}else ca(t,s,c,Jt(t))}catch(Q){ca(t,s,{then:function(){},status:"rejected",reason:Q},Jt())}finally{J.p=p,y!==null&&E.types!==null&&(y.types=E.types),I.T=y}}function F1(){}function Fu(t,s,a,c){if(t.tag!==5)throw Error(r(476));var h=Dg(t).queue;Rg(t,h,s,re,a===null?F1:function(){return zg(t),a(c)})}function Dg(t){var s=t.memoizedState;if(s!==null)return s;s={memoizedState:re,baseState:re,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:In,lastRenderedState:re},next:null};var a={};return s.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:In,lastRenderedState:a},next:null},t.memoizedState=s,t=t.alternate,t!==null&&(t.memoizedState=s),s}function zg(t){var s=Dg(t);s.next===null&&(s=t.alternate.memoizedState),ca(t,s.next.queue,{},Jt())}function Qu(){return dt(Aa)}function Ug(){return Pe().memoizedState}function Hg(){return Pe().memoizedState}function Q1(t){for(var s=t.return;s!==null;){switch(s.tag){case 24:case 3:var a=Jt();t=gi(a);var c=mi(s,t,a);c!==null&&(Ht(c,s,a),sa(c,s,a)),s={cache:Eu()},t.payload=s;return}s=s.return}}function P1(t,s,a){var c=Jt();a={lane:c,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Pl(t)?qg(s,a):(a=du(t,s,a,c),a!==null&&(Ht(a,t,c),$g(a,s,c)))}function Bg(t,s,a){var c=Jt();ca(t,s,a,c)}function ca(t,s,a,c){var h={lane:c,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(Pl(t))qg(s,h);else{var p=t.alternate;if(t.lanes===0&&(p===null||p.lanes===0)&&(p=s.lastRenderedReducer,p!==null))try{var y=s.lastRenderedState,E=p(y,a);if(h.hasEagerState=!0,h.eagerState=E,Kt(E,y))return Ml(t,s,h,0),De===null&&kl(),!1}catch{}finally{}if(a=du(t,s,h,c),a!==null)return Ht(a,t,c),$g(a,s,c),!0}return!1}function Pu(t,s,a,c){if(c={lane:2,revertLane:kf(),gesture:null,action:c,hasEagerState:!1,eagerState:null,next:null},Pl(t)){if(s)throw Error(r(479))}else s=du(t,a,c,2),s!==null&&Ht(s,t,2)}function Pl(t){var s=t.alternate;return t===de||s!==null&&s===de}function qg(t,s){Gs=Vl=!0;var a=t.pending;a===null?s.next=s:(s.next=a.next,a.next=s),t.pending=s}function $g(t,s,a){if((a&4194048)!==0){var c=s.lanes;c&=t.pendingLanes,a|=c,s.lanes=a,Xd(t,a)}}var ua={readContext:dt,use:Xl,useCallback:Ye,useContext:Ye,useEffect:Ye,useImperativeHandle:Ye,useLayoutEffect:Ye,useInsertionEffect:Ye,useMemo:Ye,useReducer:Ye,useRef:Ye,useState:Ye,useDebugValue:Ye,useDeferredValue:Ye,useTransition:Ye,useSyncExternalStore:Ye,useId:Ye,useHostTransitionStatus:Ye,useFormState:Ye,useActionState:Ye,useOptimistic:Ye,useMemoCache:Ye,useCacheRefresh:Ye};ua.useEffectEvent=Ye;var Ig={readContext:dt,use:Xl,useCallback:function(t,s){return Nt().memoizedState=[t,s===void 0?null:s],t},useContext:dt,useEffect:Tg,useImperativeHandle:function(t,s,a){a=a!=null?a.concat([t]):null,Fl(4194308,4,kg.bind(null,s,t),a)},useLayoutEffect:function(t,s){return Fl(4194308,4,t,s)},useInsertionEffect:function(t,s){Fl(4,2,t,s)},useMemo:function(t,s){var a=Nt();s=s===void 0?null:s;var c=t();if(is){Tn(!0);try{t()}finally{Tn(!1)}}return a.memoizedState=[c,s],c},useReducer:function(t,s,a){var c=Nt();if(a!==void 0){var h=a(s);if(is){Tn(!0);try{a(s)}finally{Tn(!1)}}}else h=s;return c.memoizedState=c.baseState=h,t={pending:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:h},c.queue=t,t=t.dispatch=P1.bind(null,de,t),[c.memoizedState,t]},useRef:function(t){var s=Nt();return t={current:t},s.memoizedState=t},useState:function(t){t=Vu(t);var s=t.queue,a=Bg.bind(null,de,s);return s.dispatch=a,[t.memoizedState,a]},useDebugValue:Xu,useDeferredValue:function(t,s){var a=Nt();return Yu(a,t,s)},useTransition:function(){var t=Vu(!1);return t=Rg.bind(null,de,t.queue,!0,!1),Nt().memoizedState=t,[!1,t]},useSyncExternalStore:function(t,s,a){var c=de,h=Nt();if(we){if(a===void 0)throw Error(r(407));a=a()}else{if(a=s(),De===null)throw Error(r(349));(ve&127)!==0||cg(c,s,a)}h.memoizedState=a;var p={value:a,getSnapshot:s};return h.queue=p,Tg(fg.bind(null,c,p,t),[t]),c.flags|=2048,Xs(9,{destroy:void 0},ug.bind(null,c,p,a,s),null),a},useId:function(){var t=Nt(),s=De.identifierPrefix;if(we){var a=Cn,c=An;a=(c&~(1<<32-Ct(c)-1)).toString(32)+a,s="_"+s+"R_"+a,a=Gl++,0<\/script>",p=p.removeChild(p.firstChild);break;case"select":p=typeof c.is=="string"?y.createElement("select",{is:c.is}):y.createElement("select"),c.multiple?p.multiple=!0:c.size&&(p.size=c.size);break;default:p=typeof c.is=="string"?y.createElement(h,{is:c.is}):y.createElement(h)}}p[ft]=s,p[jt]=c;e:for(y=s.child;y!==null;){if(y.tag===5||y.tag===6)p.appendChild(y.stateNode);else if(y.tag!==4&&y.tag!==27&&y.child!==null){y.child.return=y,y=y.child;continue}if(y===s)break e;for(;y.sibling===null;){if(y.return===null||y.return===s)break e;y=y.return}y.sibling.return=y.return,y=y.sibling}s.stateNode=p;e:switch(gt(p,h,c),h){case"button":case"input":case"select":case"textarea":c=!!c.autoFocus;break e;case"img":c=!0;break e;default:c=!1}c&&Gn(s)}}return Be(s),ff(s,s.type,t===null?null:t.memoizedProps,s.pendingProps,a),null;case 6:if(t&&s.stateNode!=null)t.memoizedProps!==c&&Gn(s);else{if(typeof c!="string"&&s.stateNode===null)throw Error(r(166));if(t=he.current,Us(s)){if(t=s.stateNode,a=s.memoizedProps,c=null,h=ht,h!==null)switch(h.tag){case 27:case 5:c=h.memoizedProps}t[ft]=s,t=!!(t.nodeValue===a||c!==null&&c.suppressHydrationWarning===!0||ly(t.nodeValue,a)),t||hi(s,!0)}else t=yo(t).createTextNode(c),t[ft]=s,s.stateNode=t}return Be(s),null;case 31:if(a=s.memoizedState,t===null||t.memoizedState!==null){if(c=Us(s),a!==null){if(t===null){if(!c)throw Error(r(318));if(t=s.memoizedState,t=t!==null?t.dehydrated:null,!t)throw Error(r(557));t[ft]=s}else Pi(),(s.flags&128)===0&&(s.memoizedState=null),s.flags|=4;Be(s),t=!1}else a=Su(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=a),t=!0;if(!t)return s.flags&256?(Ft(s),s):(Ft(s),null);if((s.flags&128)!==0)throw Error(r(558))}return Be(s),null;case 13:if(c=s.memoizedState,t===null||t.memoizedState!==null&&t.memoizedState.dehydrated!==null){if(h=Us(s),c!==null&&c.dehydrated!==null){if(t===null){if(!h)throw Error(r(318));if(h=s.memoizedState,h=h!==null?h.dehydrated:null,!h)throw Error(r(317));h[ft]=s}else Pi(),(s.flags&128)===0&&(s.memoizedState=null),s.flags|=4;Be(s),h=!1}else h=Su(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=h),h=!0;if(!h)return s.flags&256?(Ft(s),s):(Ft(s),null)}return Ft(s),(s.flags&128)!==0?(s.lanes=a,s):(a=c!==null,t=t!==null&&t.memoizedState!==null,a&&(c=s.child,h=null,c.alternate!==null&&c.alternate.memoizedState!==null&&c.alternate.memoizedState.cachePool!==null&&(h=c.alternate.memoizedState.cachePool.pool),p=null,c.memoizedState!==null&&c.memoizedState.cachePool!==null&&(p=c.memoizedState.cachePool.pool),p!==h&&(c.flags|=2048)),a!==t&&a&&(s.child.flags|=8192),to(s,s.updateQueue),Be(s),null);case 4:return ke(),t===null&&Lf(s.stateNode.containerInfo),Be(s),null;case 10:return qn(s.type),Be(s),null;case 19:if(Y(Qe),c=s.memoizedState,c===null)return Be(s),null;if(h=(s.flags&128)!==0,p=c.rendering,p===null)if(h)ha(c,!1);else{if(Fe!==0||t!==null&&(t.flags&128)!==0)for(t=s.child;t!==null;){if(p=Il(t),p!==null){for(s.flags|=128,ha(c,!1),t=p.updateQueue,s.updateQueue=t,to(s,t),s.subtreeFlags=0,t=a,a=s.child;a!==null;)Bp(a,t),a=a.sibling;return Z(Qe,Qe.current&1|2),we&&Hn(s,c.treeForkCount),s.child}t=t.sibling}c.tail!==null&&Tt()>ao&&(s.flags|=128,h=!0,ha(c,!1),s.lanes=4194304)}else{if(!h)if(t=Il(p),t!==null){if(s.flags|=128,h=!0,t=t.updateQueue,s.updateQueue=t,to(s,t),ha(c,!0),c.tail===null&&c.tailMode==="hidden"&&!p.alternate&&!we)return Be(s),null}else 2*Tt()-c.renderingStartTime>ao&&a!==536870912&&(s.flags|=128,h=!0,ha(c,!1),s.lanes=4194304);c.isBackwards?(p.sibling=s.child,s.child=p):(t=c.last,t!==null?t.sibling=p:s.child=p,c.last=p)}return c.tail!==null?(t=c.tail,c.rendering=t,c.tail=t.sibling,c.renderingStartTime=Tt(),t.sibling=null,a=Qe.current,Z(Qe,h?a&1|2:a&1),we&&Hn(s,c.treeForkCount),t):(Be(s),null);case 22:case 23:return Ft(s),Lu(),c=s.memoizedState!==null,t!==null?t.memoizedState!==null!==c&&(s.flags|=8192):c&&(s.flags|=8192),c?(a&536870912)!==0&&(s.flags&128)===0&&(Be(s),s.subtreeFlags&6&&(s.flags|=8192)):Be(s),a=s.updateQueue,a!==null&&to(s,a.retryQueue),a=null,t!==null&&t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),c=null,s.memoizedState!==null&&s.memoizedState.cachePool!==null&&(c=s.memoizedState.cachePool.pool),c!==a&&(s.flags|=2048),t!==null&&Y(Wi),null;case 24:return a=null,t!==null&&(a=t.memoizedState.cache),s.memoizedState.cache!==a&&(s.flags|=2048),qn(We),Be(s),null;case 25:return null;case 30:return null}throw Error(r(156,s.tag))}function tw(t,s){switch(bu(s),s.tag){case 1:return t=s.flags,t&65536?(s.flags=t&-65537|128,s):null;case 3:return qn(We),ke(),t=s.flags,(t&65536)!==0&&(t&128)===0?(s.flags=t&-65537|128,s):null;case 26:case 27:case 5:return fe(s),null;case 31:if(s.memoizedState!==null){if(Ft(s),s.alternate===null)throw Error(r(340));Pi()}return t=s.flags,t&65536?(s.flags=t&-65537|128,s):null;case 13:if(Ft(s),t=s.memoizedState,t!==null&&t.dehydrated!==null){if(s.alternate===null)throw Error(r(340));Pi()}return t=s.flags,t&65536?(s.flags=t&-65537|128,s):null;case 19:return Y(Qe),null;case 4:return ke(),null;case 10:return qn(s.type),null;case 22:case 23:return Ft(s),Lu(),t!==null&&Y(Wi),t=s.flags,t&65536?(s.flags=t&-65537|128,s):null;case 24:return qn(We),null;case 25:return null;default:return null}}function hm(t,s){switch(bu(s),s.tag){case 3:qn(We),ke();break;case 26:case 27:case 5:fe(s);break;case 4:ke();break;case 31:s.memoizedState!==null&&Ft(s);break;case 13:Ft(s);break;case 19:Y(Qe);break;case 10:qn(s.type);break;case 22:case 23:Ft(s),Lu(),t!==null&&Y(Wi);break;case 24:qn(We)}}function da(t,s){try{var a=s.updateQueue,c=a!==null?a.lastEffect:null;if(c!==null){var h=c.next;a=h;do{if((a.tag&t)===t){c=void 0;var p=a.create,y=a.inst;c=p(),y.destroy=c}a=a.next}while(a!==h)}}catch(E){Oe(s,s.return,E)}}function vi(t,s,a){try{var c=s.updateQueue,h=c!==null?c.lastEffect:null;if(h!==null){var p=h.next;c=p;do{if((c.tag&t)===t){var y=c.inst,E=y.destroy;if(E!==void 0){y.destroy=void 0,h=s;var C=a,z=E;try{z()}catch(K){Oe(h,C,K)}}}c=c.next}while(c!==p)}}catch(K){Oe(s,s.return,K)}}function dm(t){var s=t.updateQueue;if(s!==null){var a=t.stateNode;try{ig(s,a)}catch(c){Oe(t,t.return,c)}}}function pm(t,s,a){a.props=ss(t.type,t.memoizedProps),a.state=t.memoizedState;try{a.componentWillUnmount()}catch(c){Oe(t,s,c)}}function pa(t,s){try{var a=t.ref;if(a!==null){switch(t.tag){case 26:case 27:case 5:var c=t.stateNode;break;case 30:c=t.stateNode;break;default:c=t.stateNode}typeof a=="function"?t.refCleanup=a(c):a.current=c}}catch(h){Oe(t,s,h)}}function Nn(t,s){var a=t.ref,c=t.refCleanup;if(a!==null)if(typeof c=="function")try{c()}catch(h){Oe(t,s,h)}finally{t.refCleanup=null,t=t.alternate,t!=null&&(t.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(h){Oe(t,s,h)}else a.current=null}function gm(t){var s=t.type,a=t.memoizedProps,c=t.stateNode;try{e:switch(s){case"button":case"input":case"select":case"textarea":a.autoFocus&&c.focus();break e;case"img":a.src?c.src=a.src:a.srcSet&&(c.srcset=a.srcSet)}}catch(h){Oe(t,t.return,h)}}function hf(t,s,a){try{var c=t.stateNode;_w(c,t.type,a,s),c[jt]=s}catch(h){Oe(t,t.return,h)}}function mm(t){return t.tag===5||t.tag===3||t.tag===26||t.tag===27&&Ai(t.type)||t.tag===4}function df(t){e:for(;;){for(;t.sibling===null;){if(t.return===null||mm(t.return))return null;t=t.return}for(t.sibling.return=t.return,t=t.sibling;t.tag!==5&&t.tag!==6&&t.tag!==18;){if(t.tag===27&&Ai(t.type)||t.flags&2||t.child===null||t.tag===4)continue e;t.child.return=t,t=t.child}if(!(t.flags&2))return t.stateNode}}function pf(t,s,a){var c=t.tag;if(c===5||c===6)t=t.stateNode,s?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(t,s):(s=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,s.appendChild(t),a=a._reactRootContainer,a!=null||s.onclick!==null||(s.onclick=Dn));else if(c!==4&&(c===27&&Ai(t.type)&&(a=t.stateNode,s=null),t=t.child,t!==null))for(pf(t,s,a),t=t.sibling;t!==null;)pf(t,s,a),t=t.sibling}function no(t,s,a){var c=t.tag;if(c===5||c===6)t=t.stateNode,s?a.insertBefore(t,s):a.appendChild(t);else if(c!==4&&(c===27&&Ai(t.type)&&(a=t.stateNode),t=t.child,t!==null))for(no(t,s,a),t=t.sibling;t!==null;)no(t,s,a),t=t.sibling}function ym(t){var s=t.stateNode,a=t.memoizedProps;try{for(var c=t.type,h=s.attributes;h.length;)s.removeAttributeNode(h[0]);gt(s,c,a),s[ft]=t,s[jt]=a}catch(p){Oe(t,t.return,p)}}var Kn=!1,nt=!1,gf=!1,bm=typeof WeakSet=="function"?WeakSet:Set,ct=null;function nw(t,s){if(t=t.containerInfo,zf=Eo,t=Mp(t),lu(t)){if("selectionStart"in t)var a={start:t.selectionStart,end:t.selectionEnd};else e:{a=(a=t.ownerDocument)&&a.defaultView||window;var c=a.getSelection&&a.getSelection();if(c&&c.rangeCount!==0){a=c.anchorNode;var h=c.anchorOffset,p=c.focusNode;c=c.focusOffset;try{a.nodeType,p.nodeType}catch{a=null;break e}var y=0,E=-1,C=-1,z=0,K=0,Q=t,H=null;t:for(;;){for(var q;Q!==a||h!==0&&Q.nodeType!==3||(E=y+h),Q!==p||c!==0&&Q.nodeType!==3||(C=y+c),Q.nodeType===3&&(y+=Q.nodeValue.length),(q=Q.firstChild)!==null;)H=Q,Q=q;for(;;){if(Q===t)break t;if(H===a&&++z===h&&(E=y),H===p&&++K===c&&(C=y),(q=Q.nextSibling)!==null)break;Q=H,H=Q.parentNode}Q=q}a=E===-1||C===-1?null:{start:E,end:C}}else a=null}a=a||{start:0,end:0}}else a=null;for(Uf={focusedElem:t,selectionRange:a},Eo=!1,ct=s;ct!==null;)if(s=ct,t=s.child,(s.subtreeFlags&1028)!==0&&t!==null)t.return=s,ct=t;else for(;ct!==null;){switch(s=ct,p=s.alternate,t=s.flags,s.tag){case 0:if((t&4)!==0&&(t=s.updateQueue,t=t!==null?t.events:null,t!==null))for(a=0;a title"))),gt(p,c,a),p[ft]=t,ot(p),c=p;break e;case"link":var y=Ey("link","href",h).get(c+(a.href||""));if(y){for(var E=0;ERe&&(y=Re,Re=le,le=y);var j=Np(E,le),k=Np(E,Re);if(j&&k&&(q.rangeCount!==1||q.anchorNode!==j.node||q.anchorOffset!==j.offset||q.focusNode!==k.node||q.focusOffset!==k.offset)){var D=Q.createRange();D.setStart(j.node,j.offset),q.removeAllRanges(),le>Re?(q.addRange(D),q.extend(k.node,k.offset)):(D.setEnd(k.node,k.offset),q.addRange(D))}}}}for(Q=[],q=E;q=q.parentNode;)q.nodeType===1&&Q.push({element:q,left:q.scrollLeft,top:q.scrollTop});for(typeof E.focus=="function"&&E.focus(),E=0;Ea?32:a,I.T=null,a=xf,xf=null;var p=_i,y=Pn;if(at=0,Js=_i=null,Pn=0,(Ce&6)!==0)throw Error(r(331));var E=Ce;if(Ce|=4,km(p.current),Am(p,p.current,y,a),Ce=E,Sa(0,!1),At&&typeof At.onPostCommitFiberRoot=="function")try{At.onPostCommitFiberRoot(En,p)}catch{}return!0}finally{J.p=h,I.T=c,Ym(t,s)}}function Qm(t,s,a){s=an(a,s),s=ef(t.stateNode,s,2),t=mi(t,s,2),t!==null&&(qr(t,2),kn(t))}function Oe(t,s,a){if(t.tag===3)Qm(t,t,a);else for(;s!==null;){if(s.tag===3){Qm(s,t,a);break}else if(s.tag===1){var c=s.stateNode;if(typeof s.type.getDerivedStateFromError=="function"||typeof c.componentDidCatch=="function"&&(xi===null||!xi.has(c))){t=an(a,t),a=Pg(2),c=mi(s,a,2),c!==null&&(Jg(a,c,s,t),qr(c,2),kn(c));break}}s=s.return}}function Af(t,s,a){var c=t.pingCache;if(c===null){c=t.pingCache=new rw;var h=new Set;c.set(s,h)}else h=c.get(s),h===void 0&&(h=new Set,c.set(s,h));h.has(a)||(bf=!0,h.add(a),t=uw.bind(null,t,s,a),s.then(t,t))}function uw(t,s,a){var c=t.pingCache;c!==null&&c.delete(s),t.pingedLanes|=t.suspendedLanes&a,t.warmLanes&=~a,De===t&&(ve&a)===a&&(Fe===4||Fe===3&&(ve&62914560)===ve&&300>Tt()-ro?(Ce&2)===0&&Zs(t,0):vf|=a,Ps===ve&&(Ps=0)),kn(t)}function Pm(t,s){s===0&&(s=Gd()),t=Fi(t,s),t!==null&&(qr(t,s),kn(t))}function fw(t){var s=t.memoizedState,a=0;s!==null&&(a=s.retryLane),Pm(t,a)}function hw(t,s){var a=0;switch(t.tag){case 31:case 13:var c=t.stateNode,h=t.memoizedState;h!==null&&(a=h.retryLane);break;case 19:c=t.stateNode;break;case 22:c=t.stateNode._retryCache;break;default:throw Error(r(314))}c!==null&&c.delete(s),Pm(t,a)}function dw(t,s){return ri(t,s)}var ho=null,er=null,Cf=!1,po=!1,Nf=!1,Ti=0;function kn(t){t!==er&&t.next===null&&(er===null?ho=er=t:er=er.next=t),po=!0,Cf||(Cf=!0,gw())}function Sa(t,s){if(!Nf&&po){Nf=!0;do for(var a=!1,c=ho;c!==null;){if(t!==0){var h=c.pendingLanes;if(h===0)var p=0;else{var y=c.suspendedLanes,E=c.pingedLanes;p=(1<<31-Ct(42|t)+1)-1,p&=h&~(y&~E),p=p&201326741?p&201326741|1:p?p|2:0}p!==0&&(a=!0,ey(c,p))}else p=ve,p=yl(c,c===De?p:0,c.cancelPendingCommit!==null||c.timeoutHandle!==-1),(p&3)===0||Br(c,p)||(a=!0,ey(c,p));c=c.next}while(a);Nf=!1}}function pw(){Jm()}function Jm(){po=Cf=!1;var t=0;Ti!==0&&Tw()&&(t=Ti);for(var s=Tt(),a=null,c=ho;c!==null;){var h=c.next,p=Zm(c,s);p===0?(c.next=null,a===null?ho=h:a.next=h,h===null&&(er=a)):(a=c,(t!==0||(p&3)!==0)&&(po=!0)),c=h}at!==0&&at!==5||Sa(t),Ti!==0&&(Ti=0)}function Zm(t,s){for(var a=t.suspendedLanes,c=t.pingedLanes,h=t.expirationTimes,p=t.pendingLanes&-62914561;0E)break;var K=C.transferSize,Q=C.initiatorType;K&&oy(Q)&&(C=C.responseEnd,y+=K*(C"u"?null:document;function Sy(t,s,a){var c=tr;if(c&&typeof s=="string"&&s){var h=sn(s);h='link[rel="'+t+'"][href="'+h+'"]',typeof a=="string"&&(h+='[crossorigin="'+a+'"]'),vy.has(h)||(vy.add(h),t={rel:t,crossOrigin:a,href:s},c.querySelector(h)===null&&(s=c.createElement("link"),gt(s,"link",t),ot(s),c.head.appendChild(s)))}}function Rw(t){Jn.D(t),Sy("dns-prefetch",t,null)}function Dw(t,s){Jn.C(t,s),Sy("preconnect",t,s)}function zw(t,s,a){Jn.L(t,s,a);var c=tr;if(c&&t&&s){var h='link[rel="preload"][as="'+sn(s)+'"]';s==="image"&&a&&a.imageSrcSet?(h+='[imagesrcset="'+sn(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(h+='[imagesizes="'+sn(a.imageSizes)+'"]')):h+='[href="'+sn(t)+'"]';var p=h;switch(s){case"style":p=nr(t);break;case"script":p=ir(t)}hn.has(p)||(t=m({rel:"preload",href:s==="image"&&a&&a.imageSrcSet?void 0:t,as:s},a),hn.set(p,t),c.querySelector(h)!==null||s==="style"&&c.querySelector(Ea(p))||s==="script"&&c.querySelector(Ta(p))||(s=c.createElement("link"),gt(s,"link",t),ot(s),c.head.appendChild(s)))}}function Uw(t,s){Jn.m(t,s);var a=tr;if(a&&t){var c=s&&typeof s.as=="string"?s.as:"script",h='link[rel="modulepreload"][as="'+sn(c)+'"][href="'+sn(t)+'"]',p=h;switch(c){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":p=ir(t)}if(!hn.has(p)&&(t=m({rel:"modulepreload",href:t},s),hn.set(p,t),a.querySelector(h)===null)){switch(c){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(Ta(p)))return}c=a.createElement("link"),gt(c,"link",t),ot(c),a.head.appendChild(c)}}}function Hw(t,s,a){Jn.S(t,s,a);var c=tr;if(c&&t){var h=Es(c).hoistableStyles,p=nr(t);s=s||"default";var y=h.get(p);if(!y){var E={loading:0,preload:null};if(y=c.querySelector(Ea(p)))E.loading=5;else{t=m({rel:"stylesheet",href:t,"data-precedence":s},a),(a=hn.get(p))&&Gf(t,a);var C=y=c.createElement("link");ot(C),gt(C,"link",t),C._p=new Promise(function(z,K){C.onload=z,C.onerror=K}),C.addEventListener("load",function(){E.loading|=1}),C.addEventListener("error",function(){E.loading|=2}),E.loading|=4,vo(y,s,c)}y={type:"stylesheet",instance:y,count:1,state:E},h.set(p,y)}}}function Bw(t,s){Jn.X(t,s);var a=tr;if(a&&t){var c=Es(a).hoistableScripts,h=ir(t),p=c.get(h);p||(p=a.querySelector(Ta(h)),p||(t=m({src:t,async:!0},s),(s=hn.get(h))&&Kf(t,s),p=a.createElement("script"),ot(p),gt(p,"link",t),a.head.appendChild(p)),p={type:"script",instance:p,count:1,state:null},c.set(h,p))}}function qw(t,s){Jn.M(t,s);var a=tr;if(a&&t){var c=Es(a).hoistableScripts,h=ir(t),p=c.get(h);p||(p=a.querySelector(Ta(h)),p||(t=m({src:t,async:!0,type:"module"},s),(s=hn.get(h))&&Kf(t,s),p=a.createElement("script"),ot(p),gt(p,"link",t),a.head.appendChild(p)),p={type:"script",instance:p,count:1,state:null},c.set(h,p))}}function wy(t,s,a,c){var h=(h=he.current)?bo(h):null;if(!h)throw Error(r(446));switch(t){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(s=nr(a.href),a=Es(h).hoistableStyles,c=a.get(s),c||(c={type:"style",instance:null,count:0,state:null},a.set(s,c)),c):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){t=nr(a.href);var p=Es(h).hoistableStyles,y=p.get(t);if(y||(h=h.ownerDocument||h,y={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},p.set(t,y),(p=h.querySelector(Ea(t)))&&!p._p&&(y.instance=p,y.state.loading=5),hn.has(t)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},hn.set(t,a),p||$w(h,t,a,y.state))),s&&c===null)throw Error(r(528,""));return y}if(s&&c!==null)throw Error(r(529,""));return null;case"script":return s=a.async,a=a.src,typeof a=="string"&&s&&typeof s!="function"&&typeof s!="symbol"?(s=ir(a),a=Es(h).hoistableScripts,c=a.get(s),c||(c={type:"script",instance:null,count:0,state:null},a.set(s,c)),c):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,t))}}function nr(t){return'href="'+sn(t)+'"'}function Ea(t){return'link[rel="stylesheet"]['+t+"]"}function xy(t){return m({},t,{"data-precedence":t.precedence,precedence:null})}function $w(t,s,a,c){t.querySelector('link[rel="preload"][as="style"]['+s+"]")?c.loading=1:(s=t.createElement("link"),c.preload=s,s.addEventListener("load",function(){return c.loading|=1}),s.addEventListener("error",function(){return c.loading|=2}),gt(s,"link",a),ot(s),t.head.appendChild(s))}function ir(t){return'[src="'+sn(t)+'"]'}function Ta(t){return"script[async]"+t}function _y(t,s,a){if(s.count++,s.instance===null)switch(s.type){case"style":var c=t.querySelector('style[data-href~="'+sn(a.href)+'"]');if(c)return s.instance=c,ot(c),c;var h=m({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return c=(t.ownerDocument||t).createElement("style"),ot(c),gt(c,"style",h),vo(c,a.precedence,t),s.instance=c;case"stylesheet":h=nr(a.href);var p=t.querySelector(Ea(h));if(p)return s.state.loading|=4,s.instance=p,ot(p),p;c=xy(a),(h=hn.get(h))&&Gf(c,h),p=(t.ownerDocument||t).createElement("link"),ot(p);var y=p;return y._p=new Promise(function(E,C){y.onload=E,y.onerror=C}),gt(p,"link",c),s.state.loading|=4,vo(p,a.precedence,t),s.instance=p;case"script":return p=ir(a.src),(h=t.querySelector(Ta(p)))?(s.instance=h,ot(h),h):(c=a,(h=hn.get(p))&&(c=m({},a),Kf(c,h)),t=t.ownerDocument||t,h=t.createElement("script"),ot(h),gt(h,"link",c),t.head.appendChild(h),s.instance=h);case"void":return null;default:throw Error(r(443,s.type))}else s.type==="stylesheet"&&(s.state.loading&4)===0&&(c=s.instance,s.state.loading|=4,vo(c,a.precedence,t));return s.instance}function vo(t,s,a){for(var c=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),h=c.length?c[c.length-1]:null,p=h,y=0;y title"):null)}function Iw(t,s,a){if(a===1||s.itemProp!=null)return!1;switch(t){case"meta":case"title":return!0;case"style":if(typeof s.precedence!="string"||typeof s.href!="string"||s.href==="")break;return!0;case"link":if(typeof s.rel!="string"||typeof s.href!="string"||s.href===""||s.onLoad||s.onError)break;switch(s.rel){case"stylesheet":return t=s.disabled,typeof s.precedence=="string"&&t==null;default:return!0}case"script":if(s.async&&typeof s.async!="function"&&typeof s.async!="symbol"&&!s.onLoad&&!s.onError&&s.src&&typeof s.src=="string")return!0}return!1}function Ay(t){return!(t.type==="stylesheet"&&(t.state.loading&3)===0)}function Vw(t,s,a,c){if(a.type==="stylesheet"&&(typeof c.media!="string"||matchMedia(c.media).matches!==!1)&&(a.state.loading&4)===0){if(a.instance===null){var h=nr(c.href),p=s.querySelector(Ea(h));if(p){s=p._p,s!==null&&typeof s=="object"&&typeof s.then=="function"&&(t.count++,t=wo.bind(t),s.then(t,t)),a.state.loading|=4,a.instance=p,ot(p);return}p=s.ownerDocument||s,c=xy(c),(h=hn.get(h))&&Gf(c,h),p=p.createElement("link"),ot(p);var y=p;y._p=new Promise(function(E,C){y.onload=E,y.onerror=C}),gt(p,"link",c),a.instance=p}t.stylesheets===null&&(t.stylesheets=new Map),t.stylesheets.set(a,s),(s=a.state.preload)&&(a.state.loading&3)===0&&(t.count++,a=wo.bind(t),s.addEventListener("load",a),s.addEventListener("error",a))}}var Xf=0;function Gw(t,s){return t.stylesheets&&t.count===0&&_o(t,t.stylesheets),0Xf?50:800)+s);return t.unsuspend=a,function(){t.unsuspend=null,clearTimeout(c),clearTimeout(h)}}:null}function wo(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)_o(this,this.stylesheets);else if(this.unsuspend){var t=this.unsuspend;this.unsuspend=null,t()}}}var xo=null;function _o(t,s){t.stylesheets=null,t.unsuspend!==null&&(t.count++,xo=new Map,s.forEach(Kw,t),xo=null,wo.call(t))}function Kw(t,s){if(!(s.state.loading&4)){var a=xo.get(t);if(a)var c=a.get(null);else{a=new Map,xo.set(t,a);for(var h=t.querySelectorAll("link[data-precedence],style[data-precedence]"),p=0;p"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}return n(),th.exports=gx(),th.exports}var v2=mx();const yx=new Map([["APIRequestContext.fetch",{title:'{method} "{url}"'}],["APIRequestContext.fetchResponseBody",{title:"Get response body",group:"getter"}],["APIRequestContext.fetchLog",{internal:!0}],["APIRequestContext.storageState",{title:"Get storage state",group:"configuration"}],["APIRequestContext.disposeAPIResponse",{internal:!0}],["APIRequestContext.dispose",{internal:!0}],["LocalUtils.zip",{internal:!0}],["LocalUtils.harOpen",{internal:!0}],["LocalUtils.harLookup",{internal:!0}],["LocalUtils.harClose",{internal:!0}],["LocalUtils.harUnzip",{internal:!0}],["LocalUtils.connect",{internal:!0}],["LocalUtils.tracingStarted",{internal:!0}],["LocalUtils.addStackToTracingNoReply",{internal:!0}],["LocalUtils.traceDiscarded",{internal:!0}],["LocalUtils.globToRegex",{internal:!0}],["Root.initialize",{internal:!0}],["Playwright.newRequest",{title:"Create request context"}],["DebugController.initialize",{internal:!0}],["DebugController.setReportStateChanged",{internal:!0}],["DebugController.setRecorderMode",{internal:!0}],["DebugController.highlight",{internal:!0}],["DebugController.hideHighlight",{internal:!0}],["DebugController.resume",{internal:!0}],["DebugController.kill",{internal:!0}],["SocksSupport.socksConnected",{internal:!0}],["SocksSupport.socksFailed",{internal:!0}],["SocksSupport.socksData",{internal:!0}],["SocksSupport.socksError",{internal:!0}],["SocksSupport.socksEnd",{internal:!0}],["BrowserType.launch",{title:"Launch browser"}],["BrowserType.launchPersistentContext",{title:"Launch persistent context"}],["BrowserType.connectOverCDP",{title:"Connect over CDP"}],["BrowserType.connectOverCDPTransport",{title:"Connect over CDP transport"}],["Browser.startServer",{title:"Start server"}],["Browser.stopServer",{title:"Stop server"}],["Browser.close",{title:"Close browser",pause:!0}],["Browser.killForTests",{internal:!0}],["Browser.defaultUserAgentForTest",{internal:!0}],["Browser.newContext",{title:"Create context"}],["Browser.newContextForReuse",{internal:!0}],["Browser.disconnectFromReusedContext",{internal:!0}],["Browser.newBrowserCDPSession",{title:"Create CDP session",group:"configuration"}],["Browser.startTracing",{title:"Start browser tracing",group:"configuration"}],["Browser.stopTracing",{title:"Stop browser tracing",group:"configuration"}],["EventTarget.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["BrowserContext.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["Page.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["Worker.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["WebSocket.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["Debugger.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["ElectronApplication.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["AndroidDevice.waitForEventInfo",{title:'Wait for event "{info.event}"',snapshot:!0}],["BrowserContext.addCookies",{title:"Add cookies",group:"configuration"}],["BrowserContext.addInitScript",{title:"Add init script",group:"configuration"}],["BrowserContext.clearCookies",{title:"Clear cookies",group:"configuration"}],["BrowserContext.clearPermissions",{title:"Clear permissions",group:"configuration"}],["BrowserContext.close",{title:"Close context",pause:!0}],["BrowserContext.cookies",{title:"Get cookies",group:"getter"}],["BrowserContext.exposeBinding",{title:"Expose binding",group:"configuration"}],["BrowserContext.grantPermissions",{title:"Grant permissions",group:"configuration"}],["BrowserContext.newPage",{title:"Create page"}],["BrowserContext.registerSelectorEngine",{internal:!0}],["BrowserContext.setTestIdAttributeName",{internal:!0}],["BrowserContext.setExtraHTTPHeaders",{title:"Set extra HTTP headers",group:"configuration"}],["BrowserContext.setGeolocation",{title:"Set geolocation",group:"configuration"}],["BrowserContext.setHTTPCredentials",{title:"Set HTTP credentials",group:"configuration"}],["BrowserContext.setNetworkInterceptionPatterns",{title:"Route requests",group:"route"}],["BrowserContext.setWebSocketInterceptionPatterns",{title:"Route WebSockets",group:"route"}],["BrowserContext.setOffline",{title:"Set offline mode"}],["BrowserContext.storageState",{title:"Get storage state",group:"configuration"}],["BrowserContext.setStorageState",{title:"Set storage state",group:"configuration"}],["BrowserContext.pause",{title:"Pause"}],["BrowserContext.enableRecorder",{internal:!0}],["BrowserContext.disableRecorder",{internal:!0}],["BrowserContext.exposeConsoleApi",{internal:!0}],["BrowserContext.newCDPSession",{title:"Create CDP session",group:"configuration"}],["BrowserContext.harStart",{internal:!0}],["BrowserContext.harExport",{internal:!0}],["BrowserContext.createTempFiles",{internal:!0}],["BrowserContext.updateSubscription",{internal:!0}],["BrowserContext.clockFastForward",{title:'Fast forward clock "{ticksNumber|ticksString}"'}],["BrowserContext.clockInstall",{title:'Install clock "{timeNumber|timeString}"'}],["BrowserContext.clockPauseAt",{title:'Pause clock "{timeNumber|timeString}"'}],["BrowserContext.clockResume",{title:"Resume clock"}],["BrowserContext.clockRunFor",{title:'Run clock "{ticksNumber|ticksString}"'}],["BrowserContext.clockSetFixedTime",{title:'Set fixed time "{timeNumber|timeString}"'}],["BrowserContext.clockSetSystemTime",{title:'Set system time "{timeNumber|timeString}"'}],["Page.addInitScript",{title:"Add init script",group:"configuration"}],["Page.close",{title:"Close page",pause:!0}],["Page.clearConsoleMessages",{title:"Clear console messages"}],["Page.consoleMessages",{title:"Get console messages",group:"getter"}],["Page.emulateMedia",{title:"Emulate media",snapshot:!0,pause:!0}],["Page.exposeBinding",{title:"Expose binding",group:"configuration"}],["Page.goBack",{title:"Go back",slowMo:!0,snapshot:!0,pause:!0}],["Page.goForward",{title:"Go forward",slowMo:!0,snapshot:!0,pause:!0}],["Page.requestGC",{title:"Request garbage collection",group:"configuration"}],["Page.registerLocatorHandler",{title:"Register locator handler"}],["Page.resolveLocatorHandlerNoReply",{internal:!0}],["Page.unregisterLocatorHandler",{title:"Unregister locator handler"}],["Page.reload",{title:"Reload",slowMo:!0,snapshot:!0,pause:!0}],["Page.expectScreenshot",{title:"Expect screenshot",snapshot:!0,pause:!0}],["Page.screenshot",{title:"Screenshot",snapshot:!0,pause:!0}],["Page.setExtraHTTPHeaders",{title:"Set extra HTTP headers",group:"configuration"}],["Page.setNetworkInterceptionPatterns",{title:"Route requests",group:"route"}],["Page.setWebSocketInterceptionPatterns",{title:"Route WebSockets",group:"route"}],["Page.setViewportSize",{title:"Set viewport size",snapshot:!0,pause:!0}],["Page.keyboardDown",{title:'Key down "{key}"',slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.keyboardUp",{title:'Key up "{key}"',slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.keyboardInsertText",{title:'Insert "{text}"',slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.keyboardType",{title:'Type "{text}"',slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.keyboardPress",{title:'Press "{key}"',slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.mouseMove",{title:"Mouse move",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.mouseDown",{title:"Mouse down",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.mouseUp",{title:"Mouse up",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.mouseClick",{title:"Click",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.mouseWheel",{title:"Mouse wheel",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.touchscreenTap",{title:"Tap",slowMo:!0,snapshot:!0,pause:!0,input:!0}],["Page.clearPageErrors",{title:"Clear page errors"}],["Page.pageErrors",{title:"Get page errors",group:"getter"}],["Page.pdf",{title:"PDF"}],["Page.requests",{title:"Get network requests",group:"getter"}],["Page.startJSCoverage",{title:"Start JS coverage",group:"configuration"}],["Page.stopJSCoverage",{title:"Stop JS coverage",group:"configuration"}],["Page.startCSSCoverage",{title:"Start CSS coverage",group:"configuration"}],["Page.stopCSSCoverage",{title:"Stop CSS coverage",group:"configuration"}],["Page.bringToFront",{title:"Bring to front"}],["Page.pickLocator",{title:"Pick locator",group:"configuration"}],["Page.cancelPickLocator",{title:"Cancel pick locator",group:"configuration"}],["Page.screencastShowOverlay",{title:"Show overlay",group:"configuration"}],["Page.screencastRemoveOverlay",{title:"Remove overlay",group:"configuration"}],["Page.screencastChapter",{title:"Show chapter overlay",group:"configuration"}],["Page.screencastSetOverlayVisible",{title:"Set overlay visibility",group:"configuration"}],["Page.screencastShowActions",{title:"Show actions",group:"configuration"}],["Page.screencastHideActions",{title:"Remove actions",group:"configuration"}],["Page.screencastStart",{title:"Start screencast",group:"configuration"}],["Page.screencastStop",{title:"Stop screencast",group:"configuration"}],["Page.updateSubscription",{internal:!0}],["Page.setDockTile",{internal:!0}],["Frame.evalOnSelector",{title:"Evaluate",snapshot:!0,pause:!0}],["Frame.evalOnSelectorAll",{title:"Evaluate",snapshot:!0,pause:!0}],["Frame.addScriptTag",{title:"Add script tag",snapshot:!0,pause:!0}],["Frame.addStyleTag",{title:"Add style tag",snapshot:!0,pause:!0}],["Frame.ariaSnapshot",{title:"Aria snapshot",group:"getter"}],["Frame.blur",{title:"Blur",slowMo:!0,snapshot:!0,pause:!0}],["Frame.check",{title:"Check",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.click",{title:"Click",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.content",{title:"Get content",snapshot:!0,pause:!0}],["Frame.dragAndDrop",{title:"Drag and drop",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.dblclick",{title:"Double click",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.dispatchEvent",{title:'Dispatch "{type}"',slowMo:!0,snapshot:!0,pause:!0}],["Frame.evaluateExpression",{title:"Evaluate",snapshot:!0,pause:!0}],["Frame.evaluateExpressionHandle",{title:"Evaluate",snapshot:!0,pause:!0}],["Frame.fill",{title:'Fill "{value}"',slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.focus",{title:"Focus",slowMo:!0,snapshot:!0,pause:!0}],["Frame.frameElement",{title:"Get frame element",group:"getter"}],["Frame.resolveSelector",{internal:!0}],["Frame.highlight",{title:"Highlight element",group:"configuration"}],["Frame.getAttribute",{title:'Get attribute "{name}"',snapshot:!0,pause:!0,group:"getter"}],["Frame.goto",{title:'Navigate to "{url}"',slowMo:!0,snapshot:!0,pause:!0}],["Frame.hover",{title:"Hover",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.innerHTML",{title:"Get HTML",snapshot:!0,pause:!0,group:"getter"}],["Frame.innerText",{title:"Get inner text",snapshot:!0,pause:!0,group:"getter"}],["Frame.inputValue",{title:"Get input value",snapshot:!0,pause:!0,group:"getter"}],["Frame.isChecked",{title:"Is checked",snapshot:!0,pause:!0,group:"getter"}],["Frame.isDisabled",{title:"Is disabled",snapshot:!0,pause:!0,group:"getter"}],["Frame.isEnabled",{title:"Is enabled",snapshot:!0,pause:!0,group:"getter"}],["Frame.isHidden",{title:"Is hidden",snapshot:!0,pause:!0,group:"getter"}],["Frame.isVisible",{title:"Is visible",snapshot:!0,pause:!0,group:"getter"}],["Frame.isEditable",{title:"Is editable",snapshot:!0,pause:!0,group:"getter"}],["Frame.press",{title:'Press "{key}"',slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.querySelector",{title:"Query selector",snapshot:!0}],["Frame.querySelectorAll",{title:"Query selector all",snapshot:!0}],["Frame.queryCount",{title:"Query count",snapshot:!0,pause:!0}],["Frame.selectOption",{title:"Select option",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.setContent",{title:"Set content",snapshot:!0,pause:!0}],["Frame.setInputFiles",{title:"Set input files",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.tap",{title:"Tap",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.textContent",{title:"Get text content",snapshot:!0,pause:!0,group:"getter"}],["Frame.title",{title:"Get page title",group:"getter"}],["Frame.type",{title:'Type "{text}"',slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.uncheck",{title:"Uncheck",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["Frame.waitForTimeout",{title:"Wait for timeout",snapshot:!0}],["Frame.waitForFunction",{title:"Wait for function",snapshot:!0,pause:!0}],["Frame.waitForSelector",{title:"Wait for selector",snapshot:!0}],["Frame.expect",{title:'Expect "{expression}"',snapshot:!0,pause:!0}],["Worker.evaluateExpression",{title:"Evaluate"}],["Worker.evaluateExpressionHandle",{title:"Evaluate"}],["Worker.updateSubscription",{internal:!0}],["Disposable.dispose",{internal:!0}],["JSHandle.dispose",{internal:!0}],["ElementHandle.dispose",{internal:!0}],["JSHandle.evaluateExpression",{title:"Evaluate",snapshot:!0,pause:!0}],["ElementHandle.evaluateExpression",{title:"Evaluate",snapshot:!0,pause:!0}],["JSHandle.evaluateExpressionHandle",{title:"Evaluate",snapshot:!0,pause:!0}],["ElementHandle.evaluateExpressionHandle",{title:"Evaluate",snapshot:!0,pause:!0}],["JSHandle.getPropertyList",{title:"Get property list",group:"getter"}],["ElementHandle.getPropertyList",{title:"Get property list",group:"getter"}],["JSHandle.getProperty",{title:"Get JS property",group:"getter"}],["ElementHandle.getProperty",{title:"Get JS property",group:"getter"}],["JSHandle.jsonValue",{title:"Get JSON value",group:"getter"}],["ElementHandle.jsonValue",{title:"Get JSON value",group:"getter"}],["ElementHandle.evalOnSelector",{title:"Evaluate",snapshot:!0,pause:!0}],["ElementHandle.evalOnSelectorAll",{title:"Evaluate",snapshot:!0,pause:!0}],["ElementHandle.boundingBox",{title:"Get bounding box",snapshot:!0,pause:!0}],["ElementHandle.check",{title:"Check",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.click",{title:"Click",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.contentFrame",{title:"Get content frame",group:"getter"}],["ElementHandle.dblclick",{title:"Double click",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.dispatchEvent",{title:"Dispatch event",slowMo:!0,snapshot:!0,pause:!0}],["ElementHandle.fill",{title:'Fill "{value}"',slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.focus",{title:"Focus",slowMo:!0,snapshot:!0,pause:!0}],["ElementHandle.getAttribute",{title:"Get attribute",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.hover",{title:"Hover",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.innerHTML",{title:"Get HTML",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.innerText",{title:"Get inner text",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.inputValue",{title:"Get input value",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isChecked",{title:"Is checked",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isDisabled",{title:"Is disabled",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isEditable",{title:"Is editable",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isEnabled",{title:"Is enabled",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isHidden",{title:"Is hidden",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.isVisible",{title:"Is visible",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.ownerFrame",{title:"Get owner frame",group:"getter"}],["ElementHandle.press",{title:'Press "{key}"',slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.querySelector",{title:"Query selector",snapshot:!0}],["ElementHandle.querySelectorAll",{title:"Query selector all",snapshot:!0}],["ElementHandle.screenshot",{title:"Screenshot",snapshot:!0,pause:!0}],["ElementHandle.scrollIntoViewIfNeeded",{title:"Scroll into view",slowMo:!0,snapshot:!0,pause:!0}],["ElementHandle.selectOption",{title:"Select option",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.selectText",{title:"Select text",slowMo:!0,snapshot:!0,pause:!0}],["ElementHandle.setInputFiles",{title:"Set input files",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.tap",{title:"Tap",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.textContent",{title:"Get text content",snapshot:!0,pause:!0,group:"getter"}],["ElementHandle.type",{title:"Type",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.uncheck",{title:"Uncheck",slowMo:!0,snapshot:!0,pause:!0,input:!0,isAutoWaiting:!0}],["ElementHandle.waitForElementState",{title:"Wait for state",snapshot:!0,pause:!0}],["ElementHandle.waitForSelector",{title:"Wait for selector",snapshot:!0}],["Request.response",{internal:!0}],["Request.rawRequestHeaders",{internal:!0}],["Route.redirectNavigationRequest",{internal:!0}],["Route.abort",{title:"Abort request",group:"route"}],["Route.continue",{title:"Continue request",group:"route"}],["Route.fulfill",{title:"Fulfill request",group:"route"}],["WebSocketRoute.connect",{title:"Connect WebSocket to server",group:"route"}],["WebSocketRoute.ensureOpened",{internal:!0}],["WebSocketRoute.sendToPage",{title:"Send WebSocket message",group:"route"}],["WebSocketRoute.sendToServer",{title:"Send WebSocket message",group:"route"}],["WebSocketRoute.closePage",{internal:!0}],["WebSocketRoute.closeServer",{internal:!0}],["Response.body",{title:"Get response body",group:"getter"}],["Response.securityDetails",{internal:!0}],["Response.serverAddr",{internal:!0}],["Response.rawResponseHeaders",{internal:!0}],["Response.httpVersion",{internal:!0}],["Response.sizes",{internal:!0}],["BindingCall.reject",{internal:!0}],["BindingCall.resolve",{internal:!0}],["Debugger.requestPause",{title:"Pause on next call",group:"configuration"}],["Debugger.resume",{title:"Resume",group:"configuration"}],["Debugger.next",{title:"Step to next call",group:"configuration"}],["Debugger.runTo",{title:"Run to location",group:"configuration"}],["Dialog.accept",{title:"Accept dialog"}],["Dialog.dismiss",{title:"Dismiss dialog"}],["Tracing.tracingStart",{title:"Start tracing",group:"configuration"}],["Tracing.tracingStartChunk",{title:"Start tracing",group:"configuration"}],["Tracing.tracingGroup",{title:'Trace "{name}"'}],["Tracing.tracingGroupEnd",{title:"Group end"}],["Tracing.tracingStopChunk",{title:"Stop tracing",group:"configuration"}],["Tracing.tracingStop",{title:"Stop tracing",group:"configuration"}],["Artifact.pathAfterFinished",{internal:!0}],["Artifact.saveAs",{internal:!0}],["Artifact.saveAsStream",{internal:!0}],["Artifact.failure",{internal:!0}],["Artifact.stream",{internal:!0}],["Artifact.cancel",{internal:!0}],["Artifact.delete",{internal:!0}],["Stream.read",{internal:!0}],["Stream.close",{internal:!0}],["WritableStream.write",{internal:!0}],["WritableStream.close",{internal:!0}],["CDPSession.send",{title:"Send CDP command",group:"configuration"}],["CDPSession.detach",{title:"Detach CDP session",group:"configuration"}],["Electron.launch",{title:"Launch electron"}],["ElectronApplication.browserWindow",{internal:!0}],["ElectronApplication.evaluateExpression",{title:"Evaluate"}],["ElectronApplication.evaluateExpressionHandle",{title:"Evaluate"}],["ElectronApplication.updateSubscription",{internal:!0}],["Android.devices",{internal:!0}],["AndroidSocket.write",{internal:!0}],["AndroidSocket.close",{internal:!0}],["AndroidDevice.wait",{title:"Wait"}],["AndroidDevice.fill",{title:'Fill "{text}"'}],["AndroidDevice.tap",{title:"Tap"}],["AndroidDevice.drag",{title:"Drag"}],["AndroidDevice.fling",{title:"Fling"}],["AndroidDevice.longTap",{title:"Long tap"}],["AndroidDevice.pinchClose",{title:"Pinch close"}],["AndroidDevice.pinchOpen",{title:"Pinch open"}],["AndroidDevice.scroll",{title:"Scroll"}],["AndroidDevice.swipe",{title:"Swipe"}],["AndroidDevice.info",{internal:!0}],["AndroidDevice.screenshot",{title:"Screenshot"}],["AndroidDevice.inputType",{title:"Type"}],["AndroidDevice.inputPress",{title:"Press"}],["AndroidDevice.inputTap",{title:"Tap"}],["AndroidDevice.inputSwipe",{title:"Swipe"}],["AndroidDevice.inputDrag",{title:"Drag"}],["AndroidDevice.launchBrowser",{title:"Launch browser"}],["AndroidDevice.open",{title:"Open app"}],["AndroidDevice.shell",{title:"Execute shell command",group:"configuration"}],["AndroidDevice.installApk",{title:"Install apk"}],["AndroidDevice.push",{title:"Push"}],["AndroidDevice.connectToWebView",{title:"Connect to Web View"}],["AndroidDevice.close",{internal:!0}],["JsonPipe.send",{internal:!0}],["JsonPipe.close",{internal:!0}]]);function Qh(n){return yx.get(n.type+"."+n.method)}function s0(n,e){var i;return(i=bx(n,e))==null?void 0:i.replaceAll(` -`,"\\n")}function bx(n,e){if(n)for(const i of e.split("|")){if(i==="url")try{const l=new URL(n[i]);return l.protocol==="data:"?l.protocol:l.protocol==="about:"?n[i]:l.pathname+l.search}catch{if(n[i]!==void 0)return n[i]}if(i==="timeNumber"&&n[i]!==void 0)return new Date(n[i]).toString();const r=vx(n,i);if(r!==void 0)return r}}function vx(n,e){const i=e.split(".");let r=n;for(const l of i){if(typeof r!="object"||r===null)return;r=r[l]}if(r!==void 0)return String(r)}function Sx(n){var i;return(n.title??((i=Qh(n))==null?void 0:i.title)??n.method).replace(/\{([^}]+)\}/g,(r,l)=>s0(n.params,l)??r)}function wx(n){var e;return(e=Qh(n))==null?void 0:e.group}const Ba=Symbol("context"),r0=Symbol("nextInContext"),a0=Symbol("prevByEndTime"),l0=Symbol("nextByStartTime"),Zy=Symbol("events");class S2{constructor(e,i){var l,o;i.forEach(u=>xx(u));const r=i.find(u=>u.origin==="library");this.traceUri=e,this.browserName=(r==null?void 0:r.browserName)||"",this.sdkLanguage=r==null?void 0:r.sdkLanguage,this.channel=r==null?void 0:r.channel,this.testIdAttributeName=r==null?void 0:r.testIdAttributeName,this.platform=(r==null?void 0:r.platform)||"",this.playwrightVersion=(l=i.find(u=>u.playwrightVersion))==null?void 0:l.playwrightVersion,this.title=(r==null?void 0:r.title)||"",this.options=(r==null?void 0:r.options)||{},this.testTimeout=(o=i.find(u=>u.origin==="testRunner"))==null?void 0:o.testTimeout,this.actions=_x(i),this.pages=[].concat(...i.map(u=>u.pages)),this.wallTime=i.map(u=>u.wallTime).reduce((u,f)=>Math.min(u||Number.MAX_VALUE,f),Number.MAX_VALUE),this.startTime=i.map(u=>u.startTime).reduce((u,f)=>Math.min(u,f),Number.MAX_VALUE),this.endTime=i.map(u=>u.endTime).reduce((u,f)=>Math.max(u,f),Number.MIN_VALUE),this.events=[].concat(...i.map(u=>u.events)),this.stdio=[].concat(...i.map(u=>u.stdio)),this.errors=[].concat(...i.map(u=>u.errors)),this.hasSource=i.some(u=>u.hasSource),this.hasStepData=i.some(u=>u.origin==="testRunner"),this.resources=[...i.map(u=>u.resources)].flat().map(u=>({...u,id:`${u.pageref}-${u.time}-${u.request.url}`})),this.attachments=this.actions.flatMap(u=>{var f;return((f=u.attachments)==null?void 0:f.map(d=>({...d,callId:u.callId,traceUri:e})))??[]}),this.visibleAttachments=this.attachments.filter(u=>!u.name.startsWith("_")),this.events.sort((u,f)=>u.time-f.time),this.resources.sort((u,f)=>u._monotonicTime-f._monotonicTime),this.errorDescriptors=this.hasStepData?this._errorDescriptorsFromTestRunner():this._errorDescriptorsFromActions(),this.sources=Mx(this.actions,this.errorDescriptors),this.actionCounters=new Map;for(const u of this.actions)u.group=u.group??wx({type:u.class,method:u.method}),u.group&&this.actionCounters.set(u.group,1+(this.actionCounters.get(u.group)||0))}createRelativeUrl(e){const i=new URL("http://localhost/"+e);return i.searchParams.set("trace",this.traceUri),i.toString().substring(17)}failedAction(){return this.actions.findLast(e=>e.error)}filteredActions(e){const i=new Set(e);return this.actions.filter(r=>!r.group||i.has(r.group))}renderActionTree(e){const i=this.filteredActions(e??[]),{rootItem:r}=o0(i),l=[],o=(u,f)=>{const d=Sx({...u.action,type:u.action.class});l.push(`${f}${d||u.id}`);for(const g of u.children)o(g,f+" ")};return r.children.forEach(u=>o(u,"")),l}_errorDescriptorsFromActions(){var i;const e=[];for(const r of this.actions||[])(i=r.error)!=null&&i.message&&e.push({action:r,stack:r.stack,message:r.error.message});return e}_errorDescriptorsFromTestRunner(){return this.errors.filter(e=>!!e.message).map((e,i)=>({stack:e.stack,message:e.message}))}}function xx(n){for(const i of n.pages)i[Ba]=n;for(let i=0;i=0;i--){const r=n.actions[i];r[r0]=e,r.class!=="Route"&&(e=r)}for(const i of n.events)i[Ba]=n;for(const i of n.resources)i[Ba]=n}function _x(n){const e=[],i=Ex(n);e.push(...i),e.sort((r,l)=>l.parentId===r.callId?1:r.parentId===l.callId?-1:r.endTime-l.endTime);for(let r=1;rl.parentId===r.callId?-1:r.parentId===l.callId?1:r.startTime-l.startTime);for(let r=0;r+1u.origin==="library"),r=n.filter(u=>u.origin==="testRunner");if(!r.length||!i.length)return n.map(u=>u.actions.map(f=>({...f,context:u}))).flat();for(const u of i)for(const f of u.actions)e.set(f.stepId||`tmp-step@${++Wy}`,{...f,context:u});const l=Ax(r,e);l&&Tx(i,l);const o=new Map;for(const u of r)for(const f of u.actions){const d=f.stepId&&e.get(f.stepId);if(d){o.set(f.callId,d.callId),f.error&&(d.error=f.error),f.attachments&&(d.attachments=f.attachments),f.annotations&&(d.annotations=f.annotations),f.parentId&&(d.parentId=o.get(f.parentId)??f.parentId),f.group&&(d.group=f.group),d.startTime=f.startTime,d.endTime=f.endTime;continue}f.parentId&&(f.parentId=o.get(f.parentId)??f.parentId),e.set(f.stepId||`tmp-step@${++Wy}`,{...f,context:u})}return[...e.values()]}function Tx(n,e){for(const i of n){i.startTime+=e,i.endTime+=e;for(const r of i.actions)r.startTime&&(r.startTime+=e),r.endTime&&(r.endTime+=e);for(const r of i.events)r.time+=e;for(const r of i.stdio)r.timestamp+=e;for(const r of i.pages)for(const l of r.screencastFrames)l.timestamp+=e;for(const r of i.resources)r._monotonicTime&&(r._monotonicTime+=e)}}function Ax(n,e){for(const i of n)for(const r of i.actions){if(!r.startTime)continue;const l=r.stepId?e.get(r.stepId):void 0;if(l)return r.startTime-l.startTime}return 0}function o0(n){const e=new Map;for(const l of n)e.set(l.callId,{id:l.callId,parent:void 0,children:[],action:l});const i={action:{...Ox},id:"",parent:void 0,children:[]};for(const l of e.values()){i.action.startTime=Math.min(i.action.startTime,l.action.startTime),i.action.endTime=Math.max(i.action.endTime,l.action.endTime);const o=l.action.parentId&&e.get(l.action.parentId)||i;o.children.push(l),l.parent=o}const r=l=>{for(const o of l.children)o.action.stack=o.action.stack??l.action.stack,r(o)};return r(i),{rootItem:i,itemMap:e}}function c0(n){return n[Ba]}function Cx(n){return n[r0]}function eb(n){return n[a0]}function tb(n){return n[l0]}function Nx(n){let e=0,i=0;for(const r of kx(n)){if(r.type==="console"){const l=r.messageType;l==="warning"?++i:l==="error"&&++e}r.type==="event"&&r.method==="pageError"&&++e}return{errors:e,warnings:i}}function kx(n){let e=n[Zy];if(e)return e;const i=Cx(n);return e=c0(n).events.filter(r=>r.time>=n.startTime&&(!i||r.time{const d=Math.max(l,n)*window.devicePixelRatio,[g,b]=pn(o?o+"."+r+":size":void 0,d),[m,S]=pn(o?o+"."+r+":size":void 0,d),[w,T]=R.useState(null),[x,_]=ms();let A;r==="vertical"?(A=m/window.devicePixelRatio,x&&x.heightT({offset:r==="vertical"?$.clientY:$.clientX,size:A}),onMouseUp:()=>T(null),onMouseMove:$=>{if(!$.buttons)T(null);else if(w){const X=(r==="vertical"?$.clientY:$.clientX)-w.offset,U=i?w.size+X:w.size-X,B=$.target.parentElement.getBoundingClientRect(),O=Math.min(Math.max(l,U),(r==="vertical"?B.height:B.width)-l);r==="vertical"?S(O*window.devicePixelRatio):b(O*window.devicePixelRatio)}}})]})};function bt(n){if(n<0||!isFinite(n))return"-";if(n===0)return"0ms";if(n<1e3)return n.toFixed(0)+"ms";const e=n/1e3;if(e<60)return e.toFixed(1)+"s";const i=e/60;if(i<60)return i.toFixed(1)+"m";const r=i/60;return r<24?r.toFixed(1)+"h":(r/24).toFixed(1)+"d"}function Lx(n){if(n<0||!isFinite(n))return"-";if(n===0)return"0";if(n<1e3)return n.toFixed(0);const e=n/1024;if(e<1e3)return e.toFixed(1)+"K";const i=e/1024;return i<1e3?i.toFixed(1)+"M":(i/1024).toFixed(1)+"G"}const it=function(n,e,i){return n>=e&&n<=i};function Bt(n){return it(n,48,57)}function nb(n){return Bt(n)||it(n,65,70)||it(n,97,102)}function Rx(n){return it(n,65,90)}function Dx(n){return it(n,97,122)}function zx(n){return Rx(n)||Dx(n)}function Ux(n){return n>=128}function Vo(n){return zx(n)||Ux(n)||n===95}function ib(n){return Vo(n)||Bt(n)||n===45}function Hx(n){return it(n,0,8)||n===11||it(n,14,31)||n===127}function Go(n){return n===10}function Zn(n){return Go(n)||n===9||n===32}const Bx=1114111;class Ph extends Error{constructor(e){super(e),this.name="InvalidCharacterError"}}function qx(n){const e=[];for(let i=0;i=e.length?-1:e[V]},u=function(V){if(V===void 0&&(V=1),V>3)throw"Spec Error: no more than three codepoints of lookahead.";return o(i+V)},f=function(V){return V===void 0&&(V=1),i+=V,l=o(i),!0},d=function(){return i-=1,!0},g=function(V){return V===void 0&&(V=l),V===-1},b=function(){if(m(),f(),Zn(l)){for(;Zn(u());)f();return new ic}else{if(l===34)return T();if(l===35)if(ib(u())||A(u(1),u(2))){const V=new _0("");return $(u(1),u(2),u(3))&&(V.type="id"),V.value=L(),V}else return new mt(l);else return l===36?u()===61?(f(),new Gx):new mt(l):l===39?T():l===40?new S0:l===41?new Jh:l===42?u()===61?(f(),new Kx):new mt(l):l===43?U()?(d(),S()):new mt(l):l===44?new m0:l===45?U()?(d(),S()):u(1)===45&&u(2)===62?(f(2),new d0):G()?(d(),w()):new mt(l):l===46?U()?(d(),S()):new mt(l):l===58?new p0:l===59?new g0:l===60?u(1)===33&&u(2)===45&&u(3)===45?(f(3),new h0):new mt(l):l===64?$(u(1),u(2),u(3))?new x0(L()):new mt(l):l===91?new v0:l===92?N()?(d(),w()):new mt(l):l===93?new Ah:l===94?u()===61?(f(),new Vx):new mt(l):l===123?new y0:l===124?u()===61?(f(),new Ix):u()===124?(f(),new w0):new mt(l):l===125?new b0:l===126?u()===61?(f(),new $x):new mt(l):Bt(l)?(d(),S()):Vo(l)?(d(),w()):g()?new Xo:new mt(l)}},m=function(){for(;u(1)===47&&u(2)===42;)for(f(2);;)if(f(),l===42&&u()===47){f();break}else if(g())return},S=function(){const V=B();if($(u(1),u(2),u(3))){const W=new Xx;return W.value=V.value,W.repr=V.repr,W.type=V.type,W.unit=L(),W}else if(u()===37){f();const W=new A0;return W.value=V.value,W.repr=V.repr,W}else{const W=new T0;return W.value=V.value,W.repr=V.repr,W.type=V.type,W}},w=function(){const V=L();if(V.toLowerCase()==="url"&&u()===40){for(f();Zn(u(1))&&Zn(u(2));)f();return u()===34||u()===39?new Ka(V):Zn(u())&&(u(2)===34||u(2)===39)?new Ka(V):x()}else return u()===40?(f(),new Ka(V)):new Zh(V)},T=function(V){V===void 0&&(V=l);let W="";for(;f();){if(l===V||g())return new Wh(W);if(Go(l))return d(),new f0;l===92?g(u())||(Go(u())?f():W+=lt(_())):W+=lt(l)}throw new Error("Internal error")},x=function(){const V=new E0("");for(;Zn(u());)f();if(g(u()))return V;for(;f();){if(l===41||g())return V;if(Zn(l)){for(;Zn(u());)f();return u()===41||g(u())?(f(),V):(ne(),new Ko)}else{if(l===34||l===39||l===40||Hx(l))return ne(),new Ko;if(l===92)if(N())V.value+=lt(_());else return ne(),new Ko;else V.value+=lt(l)}}throw new Error("Internal error")},_=function(){if(f(),nb(l)){const V=[l];for(let ge=0;ge<5&&nb(u());ge++)f(),V.push(l);Zn(u())&&f();let W=parseInt(V.map(function(ge){return String.fromCharCode(ge)}).join(""),16);return W>Bx&&(W=65533),W}else return g()?65533:l},A=function(V,W){return!(V!==92||Go(W))},N=function(){return A(l,u())},$=function(V,W,ge){return V===45?Vo(W)||W===45||A(W,ge):Vo(V)?!0:V===92?A(V,W):!1},G=function(){return $(l,u(1),u(2))},X=function(V,W,ge){return V===43||V===45?!!(Bt(W)||W===46&&Bt(ge)):V===46?!!Bt(W):!!Bt(V)},U=function(){return X(l,u(1),u(2))},L=function(){let V="";for(;f();)if(ib(l))V+=lt(l);else if(N())V+=lt(_());else return d(),V;throw new Error("Internal parse error")},B=function(){let V="",W="integer";for((u()===43||u()===45)&&(f(),V+=lt(l));Bt(u());)f(),V+=lt(l);if(u(1)===46&&Bt(u(2)))for(f(),V+=lt(l),f(),V+=lt(l),W="number";Bt(u());)f(),V+=lt(l);const ge=u(1),Ue=u(2),I=u(3);if((ge===69||ge===101)&&Bt(Ue))for(f(),V+=lt(l),f(),V+=lt(l),W="number";Bt(u());)f(),V+=lt(l);else if((ge===69||ge===101)&&(Ue===43||Ue===45)&&Bt(I))for(f(),V+=lt(l),f(),V+=lt(l),f(),V+=lt(l),W="number";Bt(u());)f(),V+=lt(l);const J=O(V);return{type:W,value:J,repr:V}},O=function(V){return+V},ne=function(){for(;f();){if(l===41||g())return;N()&&_()}};let te=0;for(;!g(u());)if(r.push(b()),te++,te>e.length*2)throw new Error("I'm infinite-looping!");return r}class Ze{constructor(){this.tokenType=""}toJSON(){return{token:this.tokenType}}toString(){return this.tokenType}toSource(){return""+this}}class f0 extends Ze{constructor(){super(...arguments),this.tokenType="BADSTRING"}}class Ko extends Ze{constructor(){super(...arguments),this.tokenType="BADURL"}}class ic extends Ze{constructor(){super(...arguments),this.tokenType="WHITESPACE"}toString(){return"WS"}toSource(){return" "}}class h0 extends Ze{constructor(){super(...arguments),this.tokenType="CDO"}toSource(){return""}}class p0 extends Ze{constructor(){super(...arguments),this.tokenType=":"}}class g0 extends Ze{constructor(){super(...arguments),this.tokenType=";"}}class m0 extends Ze{constructor(){super(...arguments),this.tokenType=","}}class Cr extends Ze{constructor(){super(...arguments),this.value="",this.mirror=""}}class y0 extends Cr{constructor(){super(),this.tokenType="{",this.value="{",this.mirror="}"}}class b0 extends Cr{constructor(){super(),this.tokenType="}",this.value="}",this.mirror="{"}}class v0 extends Cr{constructor(){super(),this.tokenType="[",this.value="[",this.mirror="]"}}class Ah extends Cr{constructor(){super(),this.tokenType="]",this.value="]",this.mirror="["}}class S0 extends Cr{constructor(){super(),this.tokenType="(",this.value="(",this.mirror=")"}}class Jh extends Cr{constructor(){super(),this.tokenType=")",this.value=")",this.mirror="("}}class $x extends Ze{constructor(){super(...arguments),this.tokenType="~="}}class Ix extends Ze{constructor(){super(...arguments),this.tokenType="|="}}class Vx extends Ze{constructor(){super(...arguments),this.tokenType="^="}}class Gx extends Ze{constructor(){super(...arguments),this.tokenType="$="}}class Kx extends Ze{constructor(){super(...arguments),this.tokenType="*="}}class w0 extends Ze{constructor(){super(...arguments),this.tokenType="||"}}class Xo extends Ze{constructor(){super(...arguments),this.tokenType="EOF"}toSource(){return""}}class mt extends Ze{constructor(e){super(),this.tokenType="DELIM",this.value="",this.value=lt(e)}toString(){return"DELIM("+this.value+")"}toJSON(){const e=this.constructor.prototype.constructor.prototype.toJSON.call(this);return e.value=this.value,e}toSource(){return this.value==="\\"?`\\ -`:this.value}}class Nr extends Ze{constructor(){super(...arguments),this.value=""}ASCIIMatch(e){return this.value.toLowerCase()===e.toLowerCase()}toJSON(){const e=this.constructor.prototype.constructor.prototype.toJSON.call(this);return e.value=this.value,e}}class Zh extends Nr{constructor(e){super(),this.tokenType="IDENT",this.value=e}toString(){return"IDENT("+this.value+")"}toSource(){return ll(this.value)}}class Ka extends Nr{constructor(e){super(),this.tokenType="FUNCTION",this.value=e,this.mirror=")"}toString(){return"FUNCTION("+this.value+")"}toSource(){return ll(this.value)+"("}}class x0 extends Nr{constructor(e){super(),this.tokenType="AT-KEYWORD",this.value=e}toString(){return"AT("+this.value+")"}toSource(){return"@"+ll(this.value)}}class _0 extends Nr{constructor(e){super(),this.tokenType="HASH",this.value=e,this.type="unrestricted"}toString(){return"HASH("+this.value+")"}toJSON(){const e=this.constructor.prototype.constructor.prototype.toJSON.call(this);return e.value=this.value,e.type=this.type,e}toSource(){return this.type==="id"?"#"+ll(this.value):"#"+Yx(this.value)}}class Wh extends Nr{constructor(e){super(),this.tokenType="STRING",this.value=e}toString(){return'"'+C0(this.value)+'"'}}class E0 extends Nr{constructor(e){super(),this.tokenType="URL",this.value=e}toString(){return"URL("+this.value+")"}toSource(){return'url("'+C0(this.value)+'")'}}class T0 extends Ze{constructor(){super(),this.tokenType="NUMBER",this.type="integer",this.repr=""}toString(){return this.type==="integer"?"INT("+this.value+")":"NUMBER("+this.value+")"}toJSON(){const e=super.toJSON();return e.value=this.value,e.type=this.type,e.repr=this.repr,e}toSource(){return this.repr}}class A0 extends Ze{constructor(){super(),this.tokenType="PERCENTAGE",this.repr=""}toString(){return"PERCENTAGE("+this.value+")"}toJSON(){const e=this.constructor.prototype.constructor.prototype.toJSON.call(this);return e.value=this.value,e.repr=this.repr,e}toSource(){return this.repr+"%"}}class Xx extends Ze{constructor(){super(),this.tokenType="DIMENSION",this.type="integer",this.repr="",this.unit=""}toString(){return"DIM("+this.value+","+this.unit+")"}toJSON(){const e=this.constructor.prototype.constructor.prototype.toJSON.call(this);return e.value=this.value,e.type=this.type,e.repr=this.repr,e.unit=this.unit,e}toSource(){const e=this.repr;let i=ll(this.unit);return i[0].toLowerCase()==="e"&&(i[1]==="-"||it(i.charCodeAt(1),48,57))&&(i="\\65 "+i.slice(1,i.length)),e+i}}function ll(n){n=""+n;let e="";const i=n.charCodeAt(0);for(let r=0;r=128||l===45||l===95||it(l,48,57)||it(l,65,90)||it(l,97,122)?e+=n[r]:e+="\\"+n[r]}return e}function Yx(n){n=""+n;let e="";for(let i=0;i=128||r===45||r===95||it(r,48,57)||it(r,65,90)||it(r,97,122)?e+=n[i]:e+="\\"+r.toString(16)+" "}return e}function C0(n){n=""+n;let e="";for(let i=0;iO instanceof x0||O instanceof f0||O instanceof Ko||O instanceof w0||O instanceof h0||O instanceof d0||O instanceof g0||O instanceof y0||O instanceof b0||O instanceof E0||O instanceof A0);if(r)throw new qt(`Unsupported token "${r.toSource()}" while parsing css selector "${n}". Did you mean to CSS.escape it?`);let l=0;const o=new Set;function u(){return new qt(`Unexpected token "${i[l].toSource()}" while parsing css selector "${n}". Did you mean to CSS.escape it?`)}function f(){for(;i[l]instanceof ic;)l++}function d(O=l){return i[O]instanceof Zh}function g(O=l){return i[O]instanceof Wh}function b(O=l){return i[O]instanceof T0}function m(O=l){return i[O]instanceof m0}function S(O=l){return i[O]instanceof S0}function w(O=l){return i[O]instanceof Jh}function T(O=l){return i[O]instanceof Ka}function x(O=l){return i[O]instanceof mt&&i[O].value==="*"}function _(O=l){return i[O]instanceof Xo}function A(O=l){return i[O]instanceof mt&&[">","+","~"].includes(i[O].value)}function N(O=l){return m(O)||w(O)||_(O)||A(O)||i[O]instanceof ic}function $(){const O=[G()];for(;f(),!!m();)l++,O.push(G());return O}function G(){return f(),b()||g()?i[l++].value:X()}function X(){const O={simples:[]};for(f(),A()?O.simples.push({selector:{functions:[{name:"scope",args:[]}]},combinator:""}):O.simples.push({selector:U(),combinator:""});;){if(f(),A())O.simples[O.simples.length-1].combinator=i[l++].value,f();else if(N())break;O.simples.push({combinator:"",selector:U()})}return O}function U(){let O="";const ne=[];for(;!N();)if(d()||x())O+=i[l++].toSource();else if(i[l]instanceof _0)O+=i[l++].toSource();else if(i[l]instanceof mt&&i[l].value===".")if(l++,d())O+="."+i[l++].toSource();else throw u();else if(i[l]instanceof p0)if(l++,d())if(!e.has(i[l].value.toLowerCase()))O+=":"+i[l++].toSource();else{const te=i[l++].value.toLowerCase();ne.push({name:te,args:[]}),o.add(te)}else if(T()){const te=i[l++].value.toLowerCase();if(e.has(te)?(ne.push({name:te,args:$()}),o.add(te)):O+=`:${te}(${L()})`,f(),!w())throw u();l++}else throw u();else if(i[l]instanceof v0){for(O+="[",l++;!(i[l]instanceof Ah)&&!_();)O+=i[l++].toSource();if(!(i[l]instanceof Ah))throw u();O+="]",l++}else throw u();if(!O&&!ne.length)throw u();return{css:O||void 0,functions:ne}}function L(){let O="",ne=1;for(;!_()&&((S()||T())&&ne++,w()&&ne--,!!ne);)O+=i[l++].toSource();return O}const B=$();if(!_())throw u();if(B.some(O=>typeof O!="object"||!("simples"in O)))throw new qt(`Error while parsing css selector "${n}". Did you mean to CSS.escape it?`);return{selector:B,names:Array.from(o)}}const Ch=new Set(["internal:has","internal:has-not","internal:and","internal:or","internal:chain","left-of","right-of","above","below","near"]),Qx=new Set(["left-of","right-of","above","below","near"]),N0=new Set(["not","is","where","has","scope","light","visible","text","text-matches","text-is","has-text","above","below","right-of","left-of","near","nth-match"]);function ol(n){const e=Zx(n),i=[];for(const r of e.parts){if(r.name==="css"||r.name==="css:light"){r.name==="css:light"&&(r.body=":light("+r.body+")");const l=Fx(r.body,N0);i.push({name:"css",body:l.selector,source:r.body});continue}if(Ch.has(r.name)){let l,o;try{const g=JSON.parse("["+r.body+"]");if(!Array.isArray(g)||g.length<1||g.length>2||typeof g[0]!="string")throw new qt(`Malformed selector: ${r.name}=`+r.body);if(l=g[0],g.length===2){if(typeof g[1]!="number"||!Qx.has(r.name))throw new qt(`Malformed selector: ${r.name}=`+r.body);o=g[1]}}catch{throw new qt(`Malformed selector: ${r.name}=`+r.body)}const u={name:r.name,source:r.body,body:{parsed:ol(l),distance:o}},f=[...u.body.parsed.parts].reverse().find(g=>g.name==="internal:control"&&g.body==="enter-frame"),d=f?u.body.parsed.parts.indexOf(f):-1;d!==-1&&Px(u.body.parsed.parts.slice(0,d+1),i.slice(0,d+1))&&u.body.parsed.parts.splice(0,d+1),i.push(u);continue}i.push({...r,source:r.body})}if(Ch.has(i[0].name))throw new qt(`"${i[0].name}" selector cannot be first`);return{capture:e.capture,parts:i}}function Px(n,e){return On({parts:n})===On({parts:e})}function On(n,e){return typeof n=="string"?n:n.parts.map((i,r)=>{let l=!0;!e&&r!==n.capture&&(i.name==="css"||i.name==="xpath"&&i.source.startsWith("//")||i.source.startsWith(".."))&&(l=!1);const o=l?i.name+"=":"";return`${r===n.capture?"*":""}${o}${i.source}`}).join(" >> ")}function Jx(n,e){const i=(r,l)=>{for(const o of r.parts)e(o,l),Ch.has(o.name)&&i(o.body.parsed,!0)};i(n,!1)}function Zx(n){let e=0,i,r=0;const l={parts:[]},o=()=>{const f=n.substring(r,e).trim(),d=f.indexOf("=");let g,b;d!==-1&&f.substring(0,d).trim().match(/^[a-zA-Z_0-9-+:*]+$/)?(g=f.substring(0,d).trim(),b=f.substring(d+1)):f.length>1&&f[0]==='"'&&f[f.length-1]==='"'||f.length>1&&f[0]==="'"&&f[f.length-1]==="'"?(g="text",b=f):/^\(*\/\//.test(f)||f.startsWith("..")?(g="xpath",b=f):(g="css",b=f);let m=!1;if(g[0]==="*"&&(m=!0,g=g.substring(1)),l.parts.push({name:g,body:b}),m){if(l.capture!==void 0)throw new qt("Only one of the selectors can capture using * modifier");l.capture=l.parts.length-1}};if(!n.includes(">>"))return e=n.length,o(),l;const u=()=>{const d=n.substring(r,e).match(/^\s*text\s*=(.*)$/);return!!d&&!!d[1]};for(;e"&&n[e+1]===">"?(o(),e+=2,r=e):e++}return o(),l}function Xa(n,e){let i=0,r=n.length===0;const l=()=>n[i]||"",o=()=>{const _=l();return++i,r=i>=n.length,_},u=_=>{throw r?new qt(`Unexpected end of selector while parsing selector \`${n}\``):new qt(`Error while parsing selector \`${n}\` - unexpected symbol "${l()}" at position ${i}`+(_?" during "+_:""))};function f(){for(;!r&&/\s/.test(l());)o()}function d(_){return _>="€"||_>="0"&&_<="9"||_>="A"&&_<="Z"||_>="a"&&_<="z"||_>="0"&&_<="9"||_==="_"||_==="-"}function g(){let _="";for(f();!r&&d(l());)_+=o();return _}function b(_){let A=o();for(A!==_&&u("parsing quoted string");!r&&l()!==_;)l()==="\\"&&o(),A+=o();return l()!==_&&u("parsing quoted string"),A+=o(),A}function m(){o()!=="/"&&u("parsing regular expression");let _="",A=!1;for(;!r;){if(l()==="\\")_+=o(),r&&u("parsing regular expression");else if(A&&l()==="]")A=!1;else if(!A&&l()==="[")A=!0;else if(!A&&l()==="/")break;_+=o()}o()!=="/"&&u("parsing regular expression");let N="";for(;!r&&l().match(/[dgimsuy]/);)N+=o();try{return new RegExp(_,N)}catch($){throw new qt(`Error while parsing selector \`${n}\`: ${$.message}`)}}function S(){let _="";return f(),l()==="'"||l()==='"'?_=b(l()).slice(1,-1):_=g(),_||u("parsing property path"),_}function w(){f();let _="";return r||(_+=o()),!r&&_!=="="&&(_+=o()),["=","*=","^=","$=","|=","~="].includes(_)||u("parsing operator"),_}function T(){o();const _=[];for(_.push(S()),f();l()===".";)o(),_.push(S()),f();if(l()==="]")return o(),{name:_.join("."),jsonPath:_,op:"",value:null,caseSensitive:!1};const A=w();let N,$=!0;if(f(),l()==="/"){if(A!=="=")throw new qt(`Error while parsing selector \`${n}\` - cannot use ${A} in attribute with regular expression`);N=m()}else if(l()==="'"||l()==='"')N=b(l()).slice(1,-1),f(),l()==="i"||l()==="I"?($=!1,o()):(l()==="s"||l()==="S")&&($=!0,o());else{for(N="";!r&&(d(l())||l()==="+"||l()===".");)N+=o();N==="true"?N=!0:N==="false"&&(N=!1)}if(f(),l()!=="]"&&u("parsing attribute value"),o(),A!=="="&&typeof N!="string")throw new qt(`Error while parsing selector \`${n}\` - cannot use ${A} in attribute with non-string matching value - ${N}`);return{name:_.join("."),jsonPath:_,op:A,value:N,caseSensitive:$}}const x={name:"",attributes:[]};for(x.name=g(),f();l()==="[";)x.attributes.push(T()),f();if(r||u(void 0),!x.name&&!x.attributes.length)throw new qt(`Error while parsing selector \`${n}\` - selector cannot be empty`);return x}function gc(n,e="'"){const i=JSON.stringify(n),r=i.substring(1,i.length-1).replace(/\\"/g,'"');if(e==="'")return e+r.replace(/[']/g,"\\'")+e;if(e==='"')return e+r.replace(/["]/g,'\\"')+e;if(e==="`")return e+r.replace(/[`]/g,"\\`")+e;throw new Error("Invalid escape char")}function sc(n){return n.charAt(0).toUpperCase()+n.substring(1)}function k0(n){return n.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}function hr(n){return`"${n.replace(/["\\]/g,e=>"\\"+e)}"`}let ls;function Wx(){ls=new Map}function Ot(n){let e=ls==null?void 0:ls.get(n);return e===void 0&&(e=n.replace(/[\u200b\u00ad]/g,"").trim().replace(/\s+/g," "),ls==null||ls.set(n,e)),e}function mc(n){return n.replace(/(^|[^\\])(\\\\)*\\(['"`])/g,"$1$2$3")}function M0(n){return n.unicode||n.unicodeSets?String(n):String(n).replace(/(^|[^\\])(\\\\)*(["'`])/g,"$1$2\\$3").replace(/>>/g,"\\>\\>")}function $t(n,e){return typeof n!="string"?M0(n):`${JSON.stringify(n)}${e?"s":"i"}`}function Mt(n,e){return typeof n!="string"?M0(n):`"${n.replace(/\\/g,"\\\\").replace(/["]/g,'\\"')}"${e?"s":"i"}`}function e_(n,e,i=""){if(n.length<=e)return n;const r=[...n];return r.length>e?r.slice(0,e-i.length).join("")+i:r.join("")}function sb(n,e){return e_(n,e,"…")}function rc(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function t_(n,e){const i=n.length,r=e.length;let l=0,o=0;const u=Array(i+1).fill(null).map(()=>Array(r+1).fill(0));for(let f=1;f<=i;f++)for(let d=1;d<=r;d++)n[f-1]===e[d-1]&&(u[f][d]=u[f-1][d-1]+1,u[f][d]>l&&(l=u[f][d],o=f));return n.slice(o-l,o)}function O0(n,e){try{const i=ol(e),r=n_(i);return r||fs(new L0[n],i,!1,1)[0]}catch{return e}}function n_(n){const e=n.parts[n.parts.length-1];if((e==null?void 0:e.name)==="internal:describe"){const i=JSON.parse(e.body);if(typeof i=="string")return i}}function Ri(n,e,i=!1){return j0(n,e,i,1)[0]}function j0(n,e,i=!1,r=20,l){try{return fs(new L0[n](l),ol(e),i,r)}catch{return[e]}}function fs(n,e,i=!1,r=20){const l=[...e.parts],o=[];let u=i?"frame-locator":"page";for(let f=0;fn.generateLocator(g,"has",x)));continue}if(d.name==="internal:has-not"){const T=fs(n,d.body.parsed,!1,r);o.push(T.map(x=>n.generateLocator(g,"hasNot",x)));continue}if(d.name==="internal:and"){const T=fs(n,d.body.parsed,!1,r);o.push(T.map(x=>n.generateLocator(g,"and",x)));continue}if(d.name==="internal:or"){const T=fs(n,d.body.parsed,!1,r);o.push(T.map(x=>n.generateLocator(g,"or",x)));continue}if(d.name==="internal:chain"){const T=fs(n,d.body.parsed,!1,r);o.push(T.map(x=>n.generateLocator(g,"chain",x)));continue}if(d.name==="internal:label"){const{exact:T,text:x}=ja(d.body);o.push([n.generateLocator(g,"label",x,{exact:T})]);continue}if(d.name==="internal:role"){const T=Xa(d.body),x={attrs:[]};for(const _ of T.attributes)_.name==="name"?(x.exact=_.caseSensitive,x.name=_.value):(_.name==="level"&&typeof _.value=="string"&&(_.value=+_.value),x.attrs.push({name:_.name==="include-hidden"?"includeHidden":_.name,value:_.value}));o.push([n.generateLocator(g,"role",T.name,x)]);continue}if(d.name==="internal:testid"){const T=Xa(d.body),{value:x}=T.attributes[0];o.push([n.generateLocator(g,"test-id",x)]);continue}if(d.name==="internal:attr"){const T=Xa(d.body),{name:x,value:_,caseSensitive:A}=T.attributes[0],N=_,$=!!A;if(x==="placeholder"){o.push([n.generateLocator(g,"placeholder",N,{exact:$})]);continue}if(x==="alt"){o.push([n.generateLocator(g,"alt",N,{exact:$})]);continue}if(x==="title"){o.push([n.generateLocator(g,"title",N,{exact:$})]);continue}}if(d.name==="internal:control"&&d.body==="enter-frame"){const T=o[o.length-1],x=l[f-1],_=T.map(A=>n.chainLocators([A,n.generateLocator(g,"frame","")]));["xpath","css"].includes(x.name)&&_.push(n.generateLocator(g,"frame-locator",On({parts:[x]})),n.generateLocator(g,"frame-locator",On({parts:[x]},!0))),T.splice(0,T.length,..._),u="frame-locator";continue}const b=l[f+1],m=On({parts:[d]}),S=n.generateLocator(g,"default",m);if(b&&["internal:has-text","internal:has-not-text"].includes(b.name)){const{exact:T,text:x}=ja(b.body);if(!T){const _=n.generateLocator("locator",b.name==="internal:has-text"?"has-text":"has-not-text",x,{exact:T}),A={};b.name==="internal:has-text"?A.hasText=x:A.hasNotText=x;const N=n.generateLocator(g,"default",m,A);o.push([n.chainLocators([S,_]),N]),f++;continue}}let w;if(["xpath","css"].includes(d.name)){const T=On({parts:[d]},!0);w=n.generateLocator(g,"default",T)}o.push([S,w].filter(Boolean))}return i_(n,o,r)}function i_(n,e,i){const r=e.map(()=>""),l=[],o=u=>{if(u===e.length)return l.push(n.chainLocators(r)),l.lengthJSON.parse(r));for(let r=0;ru_(e,f,m.expandedItems,x||0,u),[e,f,m,x,u]),A=R.useRef(null),[N,$]=R.useState();R.useEffect(()=>{b==null||b(N)},[b,N]),R.useEffect(()=>{const U=A.current;if(!U)return;const L=()=>{rb.set(n,U.scrollTop)};return U.addEventListener("scroll",L,{passive:!0}),()=>U.removeEventListener("scroll",L)},[n]),R.useEffect(()=>{A.current&&(A.current.scrollTop=rb.get(n)||0)},[n]);const G=R.useCallback(U=>{const{expanded:L}=_.get(U);if(L){for(let B=f;B;B=B.parent)if(B===U){g==null||g(U);break}m.expandedItems.set(U.id,!1)}else m.expandedItems.set(U.id,!0);S({...m})},[_,f,g,m,S]),X=R.useCallback(U=>{const{expanded:L}=_.get(U),B=[U];for(;B.length;){const O=B.pop();B.push(...O.children),m.expandedItems.set(O.id,!L)}S({...m})},[_,m,S]);return v.jsx("div",{className:st("tree-view vbox",n+"-tree-view"),"data-testid":T||n+"-tree",children:v.jsxs("div",{className:st("tree-view-content"),role:_.size>0?"tree":void 0,tabIndex:0,onKeyDown:U=>{if(f&&U.key==="Enter"){d==null||d(f);return}if(U.key!=="ArrowDown"&&U.key!=="ArrowUp"&&U.key!=="ArrowLeft"&&U.key!=="ArrowRight")return;if(U.stopPropagation(),U.preventDefault(),f&&U.key==="ArrowLeft"){const{expanded:B,parent:O}=_.get(f);B?(m.expandedItems.set(f.id,!1),S({...m})):O&&(g==null||g(O));return}if(f&&U.key==="ArrowRight"){f.children.length&&(m.expandedItems.set(f.id,!0),S({...m}));return}let L=f;if(U.key==="ArrowDown"&&(f?L=_.get(f).next:_.size&&(L=[..._.keys()][0])),U.key==="ArrowUp"){if(f)L=_.get(f).prev;else if(_.size){const B=[..._.keys()];L=B[B.length-1]}}b==null||b(void 0),L&&(g==null||g(L)),$(void 0)},ref:A,children:[w&&_.size===0&&v.jsx("div",{className:"tree-view-empty",children:w}),e.children.map(U=>_.get(U)&&v.jsx(R0,{item:U,treeItems:_,selectedItem:f,onSelected:g,onAccepted:d,isError:o,toggleExpanded:G,toggleSubtree:X,highlightedItem:N,setHighlightedItem:$,render:i,icon:l,title:r},U.id))]})})}function R0({item:n,treeItems:e,selectedItem:i,onSelected:r,highlightedItem:l,setHighlightedItem:o,isError:u,onAccepted:f,toggleExpanded:d,toggleSubtree:g,render:b,title:m,icon:S}){const w=R.useId(),T=R.useRef(null);R.useEffect(()=>{(i==null?void 0:i.id)===n.id&&T.current&&e0(T.current)},[n.id,i==null?void 0:i.id]);const x=e.get(n),_=x.depth,A=x.expanded;let N="codicon-blank";typeof A=="boolean"&&(N=A?"codicon-chevron-down":"codicon-chevron-right");const $=b(n),G=A&&n.children.length?n.children:[],X=m==null?void 0:m(n),U=(S==null?void 0:S(n))||"codicon-blank";return v.jsxs("div",{ref:T,role:"treeitem","aria-selected":n===i,"aria-expanded":A,"aria-controls":w,title:X,className:"vbox",style:{flex:"none"},children:[v.jsxs("div",{onDoubleClick:()=>f==null?void 0:f(n),className:st("tree-view-entry",i===n&&"selected",l===n&&"highlighted",(u==null?void 0:u(n))&&"error"),onClick:()=>r==null?void 0:r(n),onMouseEnter:()=>o(n),onMouseLeave:()=>o(void 0),children:[_?new Array(_).fill(0).map((L,B)=>v.jsx("div",{className:"tree-view-indent"},"indent-"+B)):void 0,v.jsx("div",{"aria-hidden":"true",className:"codicon "+N,style:{minWidth:16,marginRight:4},onDoubleClick:L=>{L.preventDefault(),L.stopPropagation()},onClick:L=>{L.stopPropagation(),L.preventDefault(),L.altKey?g(n):d(n)}}),S&&v.jsx("div",{className:"codicon "+U,style:{minWidth:16,marginRight:4},"aria-label":"["+U.replace("codicon","icon")+"]"}),typeof $=="string"?v.jsx("div",{style:{textOverflow:"ellipsis",overflow:"hidden"},children:$}):$]}),!!G.length&&v.jsx("div",{id:w,role:"group",children:G.map(L=>e.get(L)&&v.jsx(R0,{item:L,treeItems:e,selectedItem:i,onSelected:r,onAccepted:f,isError:u,toggleExpanded:d,toggleSubtree:g,highlightedItem:l,setHighlightedItem:o,render:b,title:m,icon:S},L.id))})]})}function Nh(n,e,i){const r=i.get(n.id);if(r!==void 0)return r;const l=e(n),o=l==="if-needed"?n.children.some(u=>Nh(u,e,i)):l;return i.set(n.id,o),o}function u_(n,e,i,r,l=()=>!0){const o=new Map;if(!Nh(n,l,o))return new Map;const u=new Map,f=new Set;for(let b=e==null?void 0:e.parent;b;b=b.parent)f.add(b.id);let d=null;const g=(b,m)=>{for(const S of b.children){if(!Nh(S,l,o))continue;const w=f.has(S.id)||i.get(S.id),T=r>m&&u.size<25&&w!==!1,x=S.children.length?w??T:void 0,_={depth:m,expanded:x,parent:n===b?null:b,next:null,prev:d};d&&(u.get(d).next=S),d=S,u.set(S,_),x&&g(S,m+1)}};return g(n,0),u}const ut=R.forwardRef(function({children:e,title:i="",icon:r,disabled:l=!1,toggled:o=!1,onClick:u=()=>{},style:f,testId:d,className:g,ariaLabel:b},m){return v.jsxs("button",{ref:m,className:st(g,"toolbar-button",r,o&&"toggled"),onMouseDown:ab,onClick:u,onDoubleClick:ab,title:i,disabled:!!l,style:f,"data-testid":d,"aria-label":b||i,children:[r&&v.jsx("span",{className:`codicon codicon-${r}`,style:e?{marginRight:5}:{}}),e]})}),ab=n=>{n.stopPropagation(),n.preventDefault()};function D0(n){return n==="scheduled"?"codicon-clock":n==="running"?"codicon-loading":n==="failed"?"codicon-error":n==="passed"?"codicon-check":n==="skipped"?"codicon-circle-slash":"codicon-circle-outline"}function f_(n){return n==="scheduled"?"Pending":n==="running"?"Running":n==="failed"?"Failed":n==="passed"?"Passed":n==="skipped"?"Skipped":"Did not run"}const h_=c_,d_=({actions:n,selectedAction:e,selectedTime:i,setSelectedTime:r,treeState:l,setTreeState:o,sdkLanguage:u,onSelected:f,onHighlighted:d,revealConsole:g,revealActionAttachment:b,isLive:m,actionFilterText:S})=>{const{rootItem:w,itemMap:T}=R.useMemo(()=>o0(n),[n]),{selectedItem:x}=R.useMemo(()=>({selectedItem:e?T.get(e.callId):void 0}),[T,e]),_=R.useCallback(U=>{var L;return!!((L=U.action.error)!=null&&L.message)},[]),A=R.useCallback(U=>r({minimum:U.action.startTime,maximum:U.action.endTime}),[r]),N=R.useCallback(U=>{var B;const L=!!b&&!!((B=U.action.attachments)!=null&&B.length);return ed(U.action,{sdkLanguage:u,revealConsole:g,revealActionAttachment:()=>b==null?void 0:b(U.action.callId),isLive:m,showDuration:!0,showBadges:!0,showAttachments:L})},[m,g,b,u]),$=R.useCallback(U=>{if(!(!i||!U.action||U.action.startTime<=i.maximum&&U.action.endTime>=i.minimum))return!1;const B=td(U.action).title;return S?B.toLowerCase().includes(S.toLowerCase())?!0:"if-needed":!0},[i,S]),G=R.useCallback(U=>{f==null||f(U.action)},[f]),X=R.useCallback(U=>{d==null||d(U==null?void 0:U.action)},[d]);return v.jsxs("div",{className:"vbox action-list-container",children:[i&&v.jsxs("div",{className:"action-list-show-all",onClick:()=>r(void 0),children:[v.jsx("span",{className:"codicon codicon-triangle-left"}),"Show all"]}),v.jsx(h_,{name:"actions",rootItem:w,treeState:l,setTreeState:o,selectedItem:x,onSelected:G,onHighlighted:X,onAccepted:A,isError:_,isVisible:$,render:N,autoExpandDepth:S!=null&&S.trim()?5:0})]})},ed=(n,e)=>{var _;const{sdkLanguage:i,revealConsole:r,revealActionAttachment:l,isLive:o,showDuration:u,showBadges:f,showAttachments:d}=e,{errors:g,warnings:b}=Nx(n),m=n.params.selector?O0(i||"javascript",n.params.selector):void 0,S=n.class==="Test"&&n.method==="test.step"&&((_=n.annotations)==null?void 0:_.some(A=>A.type==="skip"));let w="";n.endTime?w=bt(n.endTime-n.startTime):n.error?w="Timed out":o||(w="-");const{elements:T,title:x}=td(n);return v.jsxs("div",{className:"action-title vbox",children:[v.jsxs("div",{className:"hbox",children:[v.jsx("span",{className:"action-title-method",title:x,children:T}),(u||f||d||S)&&v.jsx("div",{className:"spacer"}),d&&v.jsx(ut,{icon:"attach",title:"Open Attachment",onClick:()=>l==null?void 0:l()}),u&&!S&&v.jsx("div",{className:"action-duration",children:w||v.jsx("span",{className:"codicon codicon-loading"})}),S&&v.jsx("span",{className:st("action-skipped","codicon",D0("skipped")),title:"skipped"}),f&&v.jsxs("div",{className:"action-icons",onClick:()=>r==null?void 0:r(),children:[!!g&&v.jsxs("div",{className:"action-icon",children:[v.jsx("span",{className:"codicon codicon-error"}),v.jsx("span",{className:"action-icon-value",children:g})]}),!!b&&v.jsxs("div",{className:"action-icon",children:[v.jsx("span",{className:"codicon codicon-warning"}),v.jsx("span",{className:"action-icon-value",children:b})]})]})]}),m&&v.jsx("div",{className:"action-title-selector",title:m,children:m})]})};function td(n,e){var g;let i=n.title??((g=Qh({type:n.class,method:n.method}))==null?void 0:g.title)??n.method;i=i.replace(/\n/g," ");const r=[],l=[];let o=0;const u=/\{([^}]+)\}/g;let f;for(;(f=u.exec(i))!==null;){const[b,m]=f,S=i.slice(o,f.index);r.push(S),l.push(S);const w=s0(n.params,m);w===void 0?(r.push(b),l.push(b)):f.index===0?(r.push(w),l.push(w)):(r.push(v.jsx("span",{className:"action-title-param",children:w},r.length)),l.push(w)),o=f.index+b.length}if(o{const[i,r]=R.useState("copy"),l=R.useCallback(()=>{(typeof n=="function"?n():Promise.resolve(n)).then(u=>{navigator.clipboard.writeText(u).then(()=>{r("check"),setTimeout(()=>{r("copy")},3e3)},()=>{r("close")})},()=>{r("close")})},[n]);return v.jsx(ut,{title:e||"Copy",icon:i,onClick:l})},Yo=({value:n,description:e,copiedDescription:i=e,style:r})=>{const[l,o]=R.useState(!1),u=R.useCallback(async()=>{const f=typeof n=="function"?await n():n;await navigator.clipboard.writeText(f),o(!0),setTimeout(()=>o(!1),3e3)},[n]);return v.jsx(ut,{style:r,title:e,onClick:u,className:"copy-to-clipboard-text-button",children:l?i:e})},ys=({text:n})=>v.jsx("div",{className:"fill",style:{display:"flex",alignItems:"center",justifyContent:"center",fontSize:24,fontWeight:"bold",opacity:.5},children:n}),p_=({action:n,startTimeOffset:e,sdkLanguage:i})=>{const r=R.useMemo(()=>Object.keys((n==null?void 0:n.params)??{}).filter(f=>f!=="info"),[n]);if(!n)return v.jsx(ys,{text:"No action selected"});const l=n.startTime-e,o=bt(l),{title:u}=td(n);return v.jsxs("div",{className:"call-tab",children:[v.jsx("div",{className:"call-line",children:u}),v.jsx("div",{className:"call-section",children:"Time"}),Oo({name:"start",type:"literal",text:o}),Oo({name:"duration",type:"literal",text:g_(n)}),!!r.length&&v.jsxs(v.Fragment,{children:[v.jsx("div",{className:"call-section",children:"Parameters"}),r.map(f=>Oo(lb(n,f,n.params[f],i)))]}),!!n.result&&v.jsxs(v.Fragment,{children:[v.jsx("div",{className:"call-section",children:"Return value"}),Object.keys(n.result).map(f=>Oo(lb(n,f,n.result[f],i)))]})]})};function g_(n){return n.endTime?bt(n.endTime-n.startTime):n.error?"Timed Out":"Running"}function Oo(n){let e=n.text.replace(/\n/g,"↵");return n.type==="string"&&(e=`"${e}"`),v.jsxs("div",{className:"call-line",children:[n.name,":",v.jsx("span",{className:st("call-value",n.type),title:n.text,children:e}),["literal","string","number","object","locator"].includes(n.type)&&v.jsx(nd,{value:n.text})]},n.name)}function lb(n,e,i,r){const l=n.method.includes("eval")||n.method==="waitForFunction";if(e==="files")return{text:"",type:"string",name:e};if((e==="eventInit"||e==="expectedValue"||e==="arg"&&l)&&(i=ac(i.value,new Array(10).fill({handle:""}))),(e==="value"&&l||e==="received"&&n.method==="expect")&&(i=ac(i,new Array(10).fill({handle:""}))),e==="selector")return{text:Ri(r||"javascript",n.params.selector),type:"locator",name:"locator"};const o=typeof i;return o!=="object"||i===null?{text:String(i),type:o,name:e}:i.guid?{text:"",type:"handle",name:e}:{text:JSON.stringify(i).slice(0,1e3),type:"object",name:e}}function ac(n,e){if(n.n!==void 0)return n.n;if(n.s!==void 0)return n.s;if(n.b!==void 0)return n.b;if(n.v!==void 0){if(n.v==="undefined")return;if(n.v==="null")return null;if(n.v==="NaN")return NaN;if(n.v==="Infinity")return 1/0;if(n.v==="-Infinity")return-1/0;if(n.v==="-0")return-0}if(n.d!==void 0)return new Date(n.d);if(n.r!==void 0)return new RegExp(n.r.p,n.r.f);if(n.a!==void 0)return n.a.map(i=>ac(i,e));if(n.o!==void 0){const i={};for(const{k:r,v:l}of n.o)i[r]=ac(l,e);return i}return n.h!==void 0?e===void 0?"":e[n.h]:""}const ob=new Map;function yc({name:n,items:e=[],id:i,render:r,icon:l,isError:o,isWarning:u,isInfo:f,selectedItem:d,onAccepted:g,onSelected:b,onHighlighted:m,onIconClicked:S,noItemsMessage:w,dataTestId:T,notSelectable:x,ariaLabel:_}){const A=R.useRef(null),[N,$]=R.useState();return R.useEffect(()=>{m==null||m(N)},[m,N]),R.useEffect(()=>{const G=A.current;if(!G)return;const X=()=>{ob.set(n,G.scrollTop)};return G.addEventListener("scroll",X,{passive:!0}),()=>G.removeEventListener("scroll",X)},[n]),R.useEffect(()=>{A.current&&(A.current.scrollTop=ob.get(n)||0)},[n]),v.jsx("div",{className:st("list-view vbox",n+"-list-view"),role:e.length>0?"list":void 0,"aria-label":_,children:v.jsxs("div",{className:st("list-view-content",x&&"not-selectable"),tabIndex:0,onKeyDown:G=>{var B;if(d&&G.key==="Enter"){g==null||g(d,e.indexOf(d));return}if(G.key!=="ArrowDown"&&G.key!=="ArrowUp")return;G.stopPropagation(),G.preventDefault();const X=d?e.indexOf(d):-1;let U=X;G.key==="ArrowDown"&&(X===-1?U=0:U=Math.min(X+1,e.length-1)),G.key==="ArrowUp"&&(X===-1?U=e.length-1:U=Math.max(X-1,0));const L=(B=A.current)==null?void 0:B.children.item(U);e0(L||void 0),m==null||m(void 0),b==null||b(e[U],U),$(void 0)},ref:A,children:[w&&e.length===0&&v.jsx("div",{className:"list-view-empty",children:w}),e.map((G,X)=>{const U=r(G,X);return v.jsxs("div",{onDoubleClick:()=>g==null?void 0:g(G,X),role:"listitem",className:st("list-view-entry",d===G&&"selected",!x&&N===G&&"highlighted",(o==null?void 0:o(G,X))&&"error",(u==null?void 0:u(G,X))&&"warning",(f==null?void 0:f(G,X))&&"info"),"aria-selected":d===G,onClick:()=>b==null?void 0:b(G,X),onMouseEnter:()=>$(G),onMouseLeave:()=>$(void 0),children:[l&&v.jsx("div",{className:"codicon "+(l(G,X)||"codicon-blank"),style:{minWidth:16,marginRight:4},onDoubleClick:L=>{L.preventDefault(),L.stopPropagation()},onClick:L=>{L.stopPropagation(),L.preventDefault(),S==null||S(G,X)}}),typeof U=="string"?v.jsx("div",{style:{textOverflow:"ellipsis",overflow:"hidden"},children:U}):U]},(i==null?void 0:i(G,X))||X)})]})})}const m_=yc,y_=({action:n,isLive:e})=>{const i=R.useMemo(()=>{var u;if(!n||!n.log.length)return[];const r=n.log,l=n.context.wallTime-n.context.startTime,o=[];for(let f=0;f0?d=bt(n.endTime-g):e?d=bt(Date.now()-l-g):d="-"}o.push({message:r[f].message,time:d})}return o},[n,e]);return i.length?v.jsx(m_,{name:"log",ariaLabel:"Log entries",items:i,render:r=>v.jsxs("div",{className:"log-list-item",children:[v.jsx("span",{className:"log-list-duration",children:r.time}),r.message]}),notSelectable:!0}):v.jsx(ys,{text:"No log entries"})};function nl(n,e){const i=/(\x1b\[(\d+(;\d+)*)m)|([^\x1b]+)/g,r=[];let l,o={},u=!1,f=e==null?void 0:e.fg,d=e==null?void 0:e.bg;for(;(l=i.exec(n))!==null;){const[,,g,,b]=l;if(g){const m=+g;switch(m){case 0:o={};break;case 1:o["font-weight"]="bold";break;case 2:o.opacity="0.8";break;case 3:o["font-style"]="italic";break;case 4:o["text-decoration"]="underline";break;case 7:u=!0;break;case 8:o.display="none";break;case 9:o["text-decoration"]="line-through";break;case 22:delete o["font-weight"],delete o["font-style"],delete o.opacity,delete o["text-decoration"];break;case 23:delete o["font-weight"],delete o["font-style"],delete o.opacity;break;case 24:delete o["text-decoration"];break;case 27:u=!1;break;case 30:case 31:case 32:case 33:case 34:case 35:case 36:case 37:f=cb[m-30];break;case 39:f=e==null?void 0:e.fg;break;case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:d=cb[m-40];break;case 49:d=e==null?void 0:e.bg;break;case 53:o["text-decoration"]="overline";break;case 90:case 91:case 92:case 93:case 94:case 95:case 96:case 97:f=ub[m-90];break;case 100:case 101:case 102:case 103:case 104:case 105:case 106:case 107:d=ub[m-100];break}}else if(b){const m={...o},S=u?d:f;S!==void 0&&(m.color=S);const w=u?f:d;w!==void 0&&(m["background-color"]=w),r.push(`${b_(b)}`)}}return r.join("")}const cb={0:"var(--vscode-terminal-ansiBlack)",1:"var(--vscode-terminal-ansiRed)",2:"var(--vscode-terminal-ansiGreen)",3:"var(--vscode-terminal-ansiYellow)",4:"var(--vscode-terminal-ansiBlue)",5:"var(--vscode-terminal-ansiMagenta)",6:"var(--vscode-terminal-ansiCyan)",7:"var(--vscode-terminal-ansiWhite)"},ub={0:"var(--vscode-terminal-ansiBrightBlack)",1:"var(--vscode-terminal-ansiBrightRed)",2:"var(--vscode-terminal-ansiBrightGreen)",3:"var(--vscode-terminal-ansiBrightYellow)",4:"var(--vscode-terminal-ansiBrightBlue)",5:"var(--vscode-terminal-ansiBrightMagenta)",6:"var(--vscode-terminal-ansiBrightCyan)",7:"var(--vscode-terminal-ansiBrightWhite)"};function b_(n){return n.replace(/[&"<>]/g,e=>({"&":"&",'"':""","<":"<",">":">"})[e])}function v_(n){return Object.entries(n).map(([e,i])=>`${e}: ${i}`).join("; ")}const S_=({error:n})=>{const e=R.useMemo(()=>nl(n),[n]);return v.jsx("div",{className:"error-message",dangerouslySetInnerHTML:{__html:e||""}})},z0=({cursor:n,onPaneMouseMove:e,onPaneMouseUp:i,onPaneDoubleClick:r})=>(vt.useEffect(()=>{const l=document.createElement("div");return l.style.position="fixed",l.style.top="0",l.style.right="0",l.style.bottom="0",l.style.left="0",l.style.zIndex="9999",l.style.cursor=n,document.body.appendChild(l),e&&l.addEventListener("mousemove",e),i&&l.addEventListener("mouseup",i),r&&document.body.addEventListener("dblclick",r),()=>{e&&l.removeEventListener("mousemove",e),i&&l.removeEventListener("mouseup",i),r&&document.body.removeEventListener("dblclick",r),document.body.removeChild(l)}},[n,e,i,r]),v.jsx(v.Fragment,{})),w_={position:"absolute",top:0,right:0,bottom:0,left:0},U0=({orientation:n,offsets:e,setOffsets:i,resizerColor:r,resizerWidth:l,minColumnWidth:o})=>{const u=o||0,[f,d]=vt.useState(null),[g,b]=ms(),m={position:"absolute",right:n==="horizontal"?void 0:0,bottom:n==="horizontal"?0:void 0,width:n==="horizontal"?7:void 0,height:n==="horizontal"?void 0:7,borderTopWidth:n==="horizontal"?void 0:(7-l)/2,borderRightWidth:n==="horizontal"?(7-l)/2:void 0,borderBottomWidth:n==="horizontal"?void 0:(7-l)/2,borderLeftWidth:n==="horizontal"?(7-l)/2:void 0,borderColor:"transparent",borderStyle:"solid",cursor:n==="horizontal"?"ew-resize":"ns-resize"};return v.jsxs("div",{style:{position:"absolute",top:0,right:0,bottom:0,left:-(7-l)/2,zIndex:100,pointerEvents:"none"},ref:b,children:[!!f&&v.jsx(z0,{cursor:n==="horizontal"?"ew-resize":"ns-resize",onPaneMouseUp:()=>d(null),onPaneMouseMove:S=>{if(!S.buttons)d(null);else if(f){const w=n==="horizontal"?S.clientX-f.clientX:S.clientY-f.clientY,T=f.offset+w,x=f.index>0?e[f.index-1]:0,_=n==="horizontal"?g.width:g.height,A=Math.min(Math.max(x+u,T),_-u)-e[f.index];for(let N=f.index;Nv.jsx("div",{style:{...m,top:n==="horizontal"?0:S,left:n==="horizontal"?S:0,pointerEvents:"initial"},onMouseDown:T=>d({clientX:T.clientX,clientY:T.clientY,offset:S,index:w}),children:v.jsx("div",{style:{...w_,background:r}})},w))]})};async function rh(n){const e=new Image;return n&&(e.src=n,await new Promise((i,r)=>{e.onload=i,e.onerror=i})),e}const kh={backgroundImage:`linear-gradient(45deg, #80808020 25%, transparent 25%), - linear-gradient(-45deg, #80808020 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, #80808020 75%), - linear-gradient(-45deg, transparent 75%, #80808020 75%)`,backgroundSize:"20px 20px",backgroundPosition:"0 0, 0 10px, 10px -10px, -10px 0px",boxShadow:`rgb(0 0 0 / 10%) 0px 1.8px 1.9px, - rgb(0 0 0 / 15%) 0px 6.1px 6.3px, - rgb(0 0 0 / 10%) 0px -2px 4px, - rgb(0 0 0 / 15%) 0px -6.1px 12px, - rgb(0 0 0 / 25%) 0px 6px 12px`},x_=({diff:n,noTargetBlank:e,hideDetails:i})=>{const[r,l]=R.useState(n.diff?"diff":"actual"),[o,u]=R.useState(!1),[f,d]=R.useState(null),[g,b]=R.useState("Expected"),[m,S]=R.useState(null),[w,T]=R.useState(null),[x,_]=ms();R.useEffect(()=>{(async()=>{var O,ne,te,V;d(await rh((O=n.expected)==null?void 0:O.attachment.path)),b(((ne=n.expected)==null?void 0:ne.title)||"Expected"),S(await rh((te=n.actual)==null?void 0:te.attachment.path)),T(await rh((V=n.diff)==null?void 0:V.attachment.path))})()},[n]);const A=f&&m&&w,N=A?Math.max(f.naturalWidth,m.naturalWidth,200):500,$=A?Math.max(f.naturalHeight,m.naturalHeight,200):500,G=Math.min(1,(x.width-30)/N),X=Math.min(1,(x.width-50)/N/2),U=N*G,L=$*G,B={flex:"none",margin:"0 10px",cursor:"pointer",userSelect:"none"};return v.jsx("div",{"data-testid":"test-result-image-mismatch",style:{display:"flex",flexDirection:"column",alignItems:"center",flex:"auto"},ref:_,children:A&&v.jsxs(v.Fragment,{children:[v.jsxs("div",{"data-testid":"test-result-image-mismatch-tabs",style:{display:"flex",margin:"10px 0 20px"},children:[n.diff&&v.jsx("div",{style:{...B,fontWeight:r==="diff"?600:"initial"},onClick:()=>l("diff"),children:"Diff"}),v.jsx("div",{style:{...B,fontWeight:r==="actual"?600:"initial"},onClick:()=>l("actual"),children:"Actual"}),v.jsx("div",{style:{...B,fontWeight:r==="expected"?600:"initial"},onClick:()=>l("expected"),children:g}),v.jsx("div",{style:{...B,fontWeight:r==="sxs"?600:"initial"},onClick:()=>l("sxs"),children:"Side by side"}),v.jsx("div",{style:{...B,fontWeight:r==="slider"?600:"initial"},onClick:()=>l("slider"),children:"Slider"})]}),v.jsxs("div",{style:{display:"flex",justifyContent:"center",flex:"auto",minHeight:L+60},children:[n.diff&&r==="diff"&&v.jsx(Wn,{image:w,alt:"Diff",hideSize:i,canvasWidth:U,canvasHeight:L,scale:G}),n.diff&&r==="actual"&&v.jsx(Wn,{image:m,alt:"Actual",hideSize:i,canvasWidth:U,canvasHeight:L,scale:G}),n.diff&&r==="expected"&&v.jsx(Wn,{image:f,alt:g,hideSize:i,canvasWidth:U,canvasHeight:L,scale:G}),n.diff&&r==="slider"&&v.jsx(__,{expectedImage:f,actualImage:m,hideSize:i,canvasWidth:U,canvasHeight:L,scale:G,expectedTitle:g}),n.diff&&r==="sxs"&&v.jsxs("div",{style:{display:"flex"},children:[v.jsx(Wn,{image:f,title:g,hideSize:i,canvasWidth:X*N,canvasHeight:X*$,scale:X}),v.jsx(Wn,{image:o?w:m,title:o?"Diff":"Actual",onClick:()=>u(!o),hideSize:i,canvasWidth:X*N,canvasHeight:X*$,scale:X})]}),!n.diff&&r==="actual"&&v.jsx(Wn,{image:m,title:"Actual",hideSize:i,canvasWidth:U,canvasHeight:L,scale:G}),!n.diff&&r==="expected"&&v.jsx(Wn,{image:f,title:g,hideSize:i,canvasWidth:U,canvasHeight:L,scale:G}),!n.diff&&r==="sxs"&&v.jsxs("div",{style:{display:"flex"},children:[v.jsx(Wn,{image:f,title:g,canvasWidth:X*N,canvasHeight:X*$,scale:X}),v.jsx(Wn,{image:m,title:"Actual",canvasWidth:X*N,canvasHeight:X*$,scale:X})]})]}),!i&&v.jsxs("div",{style:{alignSelf:"start",lineHeight:"18px",marginLeft:"15px"},children:[v.jsx("div",{children:n.diff&&v.jsx("a",{target:"_blank",href:n.diff.attachment.path,rel:"noreferrer",children:n.diff.attachment.name})}),v.jsx("div",{children:v.jsx("a",{target:e?"":"_blank",href:n.actual.attachment.path,rel:"noreferrer",children:n.actual.attachment.name})}),v.jsx("div",{children:v.jsx("a",{target:e?"":"_blank",href:n.expected.attachment.path,rel:"noreferrer",children:n.expected.attachment.name})})]})]})})},__=({expectedImage:n,actualImage:e,canvasWidth:i,canvasHeight:r,scale:l,expectedTitle:o,hideSize:u})=>{const f={position:"absolute",top:0,left:0},[d,g]=R.useState(i/2),b=n.naturalWidth===e.naturalWidth&&n.naturalHeight===e.naturalHeight;return v.jsxs("div",{style:{flex:"none",display:"flex",alignItems:"center",flexDirection:"column",userSelect:"none"},children:[!u&&v.jsxs("div",{style:{margin:5},children:[!b&&v.jsx("span",{style:{flex:"none",margin:"0 5px"},children:"Expected "}),v.jsx("span",{children:n.naturalWidth}),v.jsx("span",{style:{flex:"none",margin:"0 5px"},children:"x"}),v.jsx("span",{children:n.naturalHeight}),!b&&v.jsx("span",{style:{flex:"none",margin:"0 5px 0 15px"},children:"Actual "}),!b&&v.jsx("span",{children:e.naturalWidth}),!b&&v.jsx("span",{style:{flex:"none",margin:"0 5px"},children:"x"}),!b&&v.jsx("span",{children:e.naturalHeight})]}),v.jsxs("div",{style:{position:"relative",width:i,height:r,margin:15,...kh},children:[v.jsx(U0,{orientation:"horizontal",offsets:[d],setOffsets:m=>g(m[0]),resizerColor:"#57606a80",resizerWidth:6}),v.jsx("img",{alt:o,style:{width:n.naturalWidth*l,height:n.naturalHeight*l},draggable:"false",src:n.src}),v.jsx("div",{style:{...f,bottom:0,overflow:"hidden",width:d,...kh},children:v.jsx("img",{alt:"Actual",style:{width:e.naturalWidth*l,height:e.naturalHeight*l},draggable:"false",src:e.src})})]})]})},Wn=({image:n,title:e,alt:i,hideSize:r,canvasWidth:l,canvasHeight:o,scale:u,onClick:f})=>v.jsxs("div",{style:{flex:"none",display:"flex",alignItems:"center",flexDirection:"column"},children:[!r&&v.jsxs("div",{style:{margin:5},children:[e&&v.jsx("span",{style:{flex:"none",margin:"0 5px"},children:e}),v.jsx("span",{children:n.naturalWidth}),v.jsx("span",{style:{flex:"none",margin:"0 5px"},children:"x"}),v.jsx("span",{children:n.naturalHeight})]}),v.jsx("div",{style:{display:"flex",flex:"none",width:l,height:o,margin:15,...kh},children:v.jsx("img",{width:n.naturalWidth*u,height:n.naturalHeight*u,alt:e||i,style:{cursor:f?"pointer":"initial"},draggable:"false",src:n.src,onClick:f})})]}),E_="modulepreload",T_=function(n,e){return new URL(n,e).href},fb={},A_=function(e,i,r){let l=Promise.resolve();if(i&&i.length>0){let u=function(b){return Promise.all(b.map(m=>Promise.resolve(m).then(S=>({status:"fulfilled",value:S}),S=>({status:"rejected",reason:S}))))};const f=document.getElementsByTagName("link"),d=document.querySelector("meta[property=csp-nonce]"),g=(d==null?void 0:d.nonce)||(d==null?void 0:d.getAttribute("nonce"));l=u(i.map(b=>{if(b=T_(b,r),b in fb)return;fb[b]=!0;const m=b.endsWith(".css"),S=m?'[rel="stylesheet"]':"";if(!!r)for(let x=f.length-1;x>=0;x--){const _=f[x];if(_.href===b&&(!m||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${b}"]${S}`))return;const T=document.createElement("link");if(T.rel=m?"stylesheet":E_,m||(T.as="script"),T.crossOrigin="",T.href=b,g&&T.setAttribute("nonce",g),document.head.appendChild(T),m)return new Promise((x,_)=>{T.addEventListener("load",x),T.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${b}`)))})}))}function o(u){const f=new Event("vite:preloadError",{cancelable:!0});if(f.payload=u,window.dispatchEvent(f),!f.defaultPrevented)throw u}return l.then(u=>{for(const f of u||[])f.status==="rejected"&&o(f.reason);return e().catch(o)})},C_=20,Er=({text:n,highlighter:e,mimeType:i,linkify:r,readOnly:l,highlight:o,revealLine:u,lineNumbers:f,isFocused:d,focusOnChange:g,wrapLines:b,onChange:m,dataTestId:S,placeholder:w})=>{const[T,x]=ms(),[_]=R.useState(A_(()=>import("./codeMirrorModule-DS0FLvoc.js"),__vite__mapDeps([0,1]),import.meta.url).then(G=>G.default)),A=R.useRef(null),[N,$]=R.useState();return R.useEffect(()=>{(async()=>{var B,O;const G=await _;k_(G);const X=x.current;if(!X)return;const U=O_(e)||M_(i)||(r?"text/linkified":"");if(A.current&&U===A.current.cm.getOption("mode")&&!!l===A.current.cm.getOption("readOnly")&&f===A.current.cm.getOption("lineNumbers")&&b===A.current.cm.getOption("lineWrapping")&&w===A.current.cm.getOption("placeholder"))return;(O=(B=A.current)==null?void 0:B.cm)==null||O.getWrapperElement().remove();const L=G(X,{value:"",mode:U,readOnly:!!l,lineNumbers:f,lineWrapping:b,placeholder:w,matchBrackets:!0,autoCloseBrackets:!0,extraKeys:{"Ctrl-F":"findPersistent","Cmd-F":"findPersistent"}});return A.current={cm:L},d&&L.focus(),$(L),L})()},[_,N,x,e,i,r,f,b,l,d,w]),R.useEffect(()=>{A.current&&A.current.cm.setSize(T.width,T.height)},[T]),R.useLayoutEffect(()=>{var U;if(!N)return;let G=!1;if(N.getValue()!==n&&(N.setValue(n),G=!0,g&&(N.execCommand("selectAll"),N.focus())),G||JSON.stringify(o)!==JSON.stringify(A.current.highlight)){for(const O of A.current.highlight||[])N.removeLineClass(O.line-1,"wrap");for(const O of o||[])N.addLineClass(O.line-1,"wrap",`source-line-${O.type}`);for(const O of A.current.widgets||[])N.removeLineWidget(O);for(const O of A.current.markers||[])O.clear();const L=[],B=[];for(const O of o||[]){if(O.type!=="subtle-error"&&O.type!=="error")continue;const ne=(U=A.current)==null?void 0:U.cm.getLine(O.line-1);if(ne){const te={};te.title=O.message||"",B.push(N.markText({line:O.line-1,ch:0},{line:O.line-1,ch:O.column||ne.length},{className:"source-line-error-underline",attributes:te}))}if(O.type==="error"){const te=document.createElement("div");te.innerHTML=nl(O.message||""),te.className="source-line-error-widget",L.push(N.addLineWidget(O.line,te,{above:!0,coverGutter:!1}))}}A.current.highlight=o,A.current.widgets=L,A.current.markers=B}typeof u=="number"&&A.current.cm.lineCount()>=u&&N.scrollIntoView({line:Math.max(0,u-1),ch:0},50);let X;return m&&(X=()=>m(N.getValue()),N.on("change",X)),()=>{X&&N.off("change",X)}},[N,n,o,u,g,m]),v.jsx("div",{"data-testid":S,className:"cm-wrapper",ref:x,onClick:N_})};function N_(n){var i;if(!(n.target instanceof HTMLElement))return;let e;n.target.classList.contains("cm-linkified")?e=n.target.textContent:n.target.classList.contains("cm-link")&&((i=n.target.nextElementSibling)!=null&&i.classList.contains("cm-url"))&&(e=n.target.nextElementSibling.textContent.slice(1,-1)),e&&(n.preventDefault(),n.stopPropagation(),window.open(e,"_blank"))}let hb=!1;function k_(n){hb||(hb=!0,n.defineSimpleMode("text/linkified",{start:[{regex:t0,token:"linkified"}]}))}function M_(n){if(n){if(n.includes("javascript")||n.includes("json"))return"javascript";if(n.includes("python"))return"python";if(n.includes("csharp"))return"text/x-csharp";if(n.includes("java"))return"text/x-java";if(n.includes("markdown"))return"markdown";if(n.includes("html")||n.includes("svg"))return"htmlmixed";if(n.includes("css"))return"css"}}function O_(n){if(n)return{javascript:"javascript",jsonl:"javascript",python:"python",csharp:"text/x-csharp",java:"text/x-java",markdown:"markdown",html:"htmlmixed",css:"css",yaml:"yaml"}[n]}function j_(n){return!!n.match(/^(application\/json|application\/.*?\+json|text\/(x-)?json)(;\s*charset=.*)?$/)}function L_(n){return!!n.match(/^(application\/xml|application\/.*?\+xml|text\/xml)(;\s*charset=.*)?$/)}function R_(n){return!!n.match(/^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$/)}const H0=({title:n,children:e,setExpanded:i,expanded:r,expandOnTitleClick:l,className:o})=>{const u=R.useId(),f=R.useId(),d=R.useCallback(()=>i(!r),[r,i]),g=v.jsx("div",{className:st("codicon",r?"codicon-chevron-down":"codicon-chevron-right"),style:{cursor:"pointer",color:"var(--vscode-foreground)",marginLeft:"5px"},onClick:l?void 0:d});return v.jsxs("div",{className:st("expandable",r&&"expanded",o),children:[l?v.jsxs("div",{id:u,role:"button","aria-expanded":r,"aria-controls":f,className:"expandable-title",onClick:d,children:[g,n]}):v.jsxs("div",{className:"expandable-title",children:[g,n]}),r&&v.jsx("div",{id:f,"aria-labelledby":u,role:"region",className:"expandable-content",children:e})]})};function B0(n){const e=[];let i=0,r;for(;(r=t0.exec(n))!==null;){const o=n.substring(i,r.index);o&&e.push(o);const u=r[0];e.push(D_(u)),i=r.index+u.length}const l=n.substring(i);return l&&e.push(l),e}function D_(n){let e=n;return e.startsWith("www.")&&(e="https://"+e),v.jsx("a",{href:e,target:"_blank",rel:"noopener noreferrer",children:n})}const q0=R.createContext(void 0),si=()=>R.useContext(q0),z_=({attachment:n,reveal:e})=>{const i=si(),[r,l]=R.useState(!1),[o,u]=R.useState(null),[f,d]=R.useState(null),[g,b]=ax(),m=R.useRef(null),S=R_(n.contentType),w=!!n.sha1||!!n.path;R.useEffect(()=>{var _;if(e)return(_=m.current)==null||_.scrollIntoView({behavior:"smooth"}),b()},[e,b]),R.useEffect(()=>{r&&o===null&&f===null&&(d("Loading ..."),fetch(bc(i,n)).then(_=>_.text()).then(_=>{u(_),d(null)}).catch(_=>{d("Failed to load: "+_.message)}))},[i,r,o,f,n]);const T=R.useMemo(()=>{const _=o?o.split(` -`).length:0;return Math.min(Math.max(5,_),20)*C_},[o]),x=v.jsxs("span",{style:{marginLeft:5},ref:m,"aria-label":n.name,children:[v.jsx("span",{children:B0(n.name)}),w&&v.jsx("a",{style:{marginLeft:5},href:Fo(i,n),children:"download"})]});return!S||!w?v.jsx("div",{style:{marginLeft:20},children:x}):v.jsxs("div",{className:st(g&&"yellow-flash"),children:[v.jsx(H0,{title:x,expanded:r,setExpanded:l,expandOnTitleClick:!0,children:f&&v.jsx("i",{children:f})}),r&&o!==null&&v.jsx("div",{className:"vbox",style:{height:T},children:v.jsx(Er,{text:o,readOnly:!0,mimeType:n.contentType,linkify:!0,lineNumbers:!0,wrapLines:!1})})]})},U_=({revealedAttachmentCallId:n})=>{const e=si(),{diffMap:i,screenshots:r,attachments:l}=R.useMemo(()=>{const o=new Set((e==null?void 0:e.visibleAttachments)??[]),u=new Set,f=new Map;for(const d of o){if(!d.path&&!d.sha1)continue;const g=d.name.match(/^(.*)-(expected|actual|diff)\.png$/);if(g){const b=g[1],m=g[2],S=f.get(b)||{expected:void 0,actual:void 0,diff:void 0};S[m]=d,f.set(b,S),o.delete(d)}else d.contentType.startsWith("image/")&&(u.add(d),o.delete(d))}return{diffMap:f,attachments:o,screenshots:u}},[e]);return!i.size&&!r.size&&!l.size?v.jsx(ys,{text:"No attachments"}):v.jsxs("div",{className:"attachments-tab",children:[[...i.values()].map(({expected:o,actual:u,diff:f})=>v.jsxs(v.Fragment,{children:[o&&u&&v.jsx("div",{className:"attachments-section",children:"Image diff"}),o&&u&&v.jsx(x_,{noTargetBlank:!0,diff:{name:"Image diff",expected:{attachment:{...o,path:Fo(e,o)},title:"Expected"},actual:{attachment:{...u,path:Fo(e,u)}},diff:f?{attachment:{...f,path:Fo(e,f)}}:void 0}})]})),r.size?v.jsx("div",{className:"attachments-section",children:"Screenshots"}):void 0,[...r.values()].map((o,u)=>{const f=bc(e,o);return v.jsxs("div",{className:"attachment-item",children:[v.jsx("div",{children:v.jsx("img",{draggable:"false",src:f})}),v.jsx("div",{children:v.jsx("a",{target:"_blank",href:f,rel:"noreferrer",children:o.name})})]},`screenshot-${u}`)}),l.size?v.jsx("div",{className:"attachments-section",children:"Attachments"}):void 0,[...l.values()].map((o,u)=>v.jsx("div",{className:"attachment-item",children:v.jsx(z_,{attachment:o,reveal:n&&o.callId===n.callId?n:void 0})},H_(o,u)))]})};function bc(n,e){return n&&e.sha1?n.createRelativeUrl(`sha1/${e.sha1}`):`file?path=${encodeURIComponent(e.path)}`}function Fo(n,e){let i=e.contentType?`&dn=${encodeURIComponent(e.name)}`:"";return e.contentType&&(i+=`&dct=${encodeURIComponent(e.contentType)}`),bc(n,e)+i}function H_(n,e){return e+"-"+(n.sha1?"sha1-"+n.sha1:"path-"+n.path)}const B_=({prompt:n})=>v.jsx(Yo,{value:n,description:"Copy prompt",copiedDescription:v.jsxs(v.Fragment,{children:["Copied ",v.jsx("span",{className:"codicon codicon-copy",style:{marginLeft:"5px"}})]}),style:{width:"120px",justifyContent:"center"}});function q_(n){return R.useMemo(()=>{if(!n)return{errors:new Map};const e=new Map;for(const i of n.errorDescriptors)e.set(i.message,i);return{errors:e}},[n])}function $_({message:n,error:e,sdkLanguage:i,revealInSource:r}){var f;let l,o;const u=(f=e.stack)==null?void 0:f[0];return u&&(l=u.file.replace(/.*[/\\](.*)/,"$1")+":"+u.line,o=u.file+":"+u.line),v.jsxs("div",{style:{display:"flex",flexDirection:"column",overflowX:"clip"},children:[v.jsxs("div",{className:"hbox",style:{alignItems:"center",padding:"5px 10px",minHeight:36,fontWeight:"bold",color:"var(--vscode-errorForeground)",flex:0},children:[e.action&&ed(e.action,{sdkLanguage:i}),l&&v.jsxs("div",{className:"action-location",children:["@ ",v.jsx("span",{title:o,onClick:()=>r(e),children:l})]})]}),v.jsx(S_,{error:n})]})}const I_=({errorsModel:n,sdkLanguage:e,revealInSource:i,wallTime:r,testRunMetadata:l})=>{const o=si(),u=Yh(async()=>{const f=o==null?void 0:o.attachments.find(g=>g.name==="error-context");if(!f)return;let d=await fetch(bc(o,f)).then(g=>g.text());if(d)return l!=null&&l.gitDiff&&(d+=` - -# Local changes - -\`\`\`diff -`+l.gitDiff+"\n```"),d},[o,l],void 0);return n.errors.size?v.jsxs("div",{className:"fill",style:{overflow:"auto"},children:[v.jsx("span",{style:{position:"absolute",right:"5px",top:"5px",zIndex:1},children:u&&v.jsx(B_,{prompt:u})}),[...n.errors.entries()].map(([f,d])=>{const g=`error-${r}-${f}`;return v.jsx($_,{message:f,error:d,revealInSource:i,sdkLanguage:e},g)})]}):v.jsx(ys,{text:"No errors"})},V_=yc;function G_(n,e){const{entries:i}=R.useMemo(()=>{if(!n)return{entries:[]};const l=[];function o(f){var b,m,S,w,T,x;const d=l[l.length-1];d&&((b=f.browserMessage)==null?void 0:b.bodyString)===((m=d.browserMessage)==null?void 0:m.bodyString)&&((S=f.browserMessage)==null?void 0:S.location)===((w=d.browserMessage)==null?void 0:w.location)&&f.browserError===d.browserError&&((T=f.nodeMessage)==null?void 0:T.html)===((x=d.nodeMessage)==null?void 0:x.html)&&f.isError===d.isError&&f.isWarning===d.isWarning&&f.timestamp-d.timestamp<1e3?d.repeat++:l.push({...f,repeat:1})}const u=[...n.events,...n.stdio].sort((f,d)=>{const g="time"in f?f.time:f.timestamp,b="time"in d?d.time:d.timestamp;return g-b});for(const f of u){if(f.type==="console"){const d=f.args&&f.args.length?X_(f.args):$0(f.text),g=f.location.url,m=`${g?g.substring(g.lastIndexOf("/")+1):""}:${f.location.lineNumber}`;o({browserMessage:{body:d,bodyString:f.text,location:m},isError:f.messageType==="error",isWarning:f.messageType==="warning",timestamp:f.time})}if(f.type==="event"&&f.method==="pageError"&&o({browserError:f.params.error,isError:!0,isWarning:!1,timestamp:f.time}),f.type==="stderr"||f.type==="stdout"){let d="";f.text&&(d=nl(f.text.trim())||""),f.base64&&(d=nl(atob(f.base64).trim())||""),o({nodeMessage:{html:d},isError:f.type==="stderr",isWarning:!1,timestamp:f.timestamp})}}return{entries:l}},[n]);return{entries:R.useMemo(()=>e?i.filter(l=>l.timestamp>=e.minimum&&l.timestamp<=e.maximum):i,[i,e])}}const K_=({consoleModel:n,boundaries:e,onEntryHovered:i,onAccepted:r})=>n.entries.length?v.jsx("div",{className:"console-tab",children:v.jsx(V_,{name:"console",onAccepted:r,onHighlighted:l=>i==null?void 0:i(l?n.entries.indexOf(l):void 0),items:n.entries,isError:l=>l.isError,isWarning:l=>l.isWarning,render:l=>{const o=bt(l.timestamp-e.minimum),u=v.jsx("span",{className:"console-time",children:o}),f=l.isError?"status-error":l.isWarning?"status-warning":"status-none",d=l.browserMessage||l.browserError?v.jsx("span",{className:st("codicon","codicon-browser",f),title:"Browser message"}):v.jsx("span",{className:st("codicon","codicon-file",f),title:"Runner message"});let g,b,m,S;const{browserMessage:w,browserError:T,nodeMessage:x}=l;if(w&&(g=w.location,b=w.body),T){const{error:_,value:A}=T;_?(b=_.message,S=_.stack):b=String(A)}return x&&(m=x.html),v.jsxs("div",{className:"console-line",children:[u,d,g&&v.jsx("span",{className:"console-location",children:g}),l.repeat>1&&v.jsx("span",{className:"console-repeat",children:l.repeat}),b&&v.jsx("span",{className:"console-line-message",children:b}),m&&v.jsx("span",{className:"console-line-message",dangerouslySetInnerHTML:{__html:m}}),S&&v.jsx("div",{className:"console-stack",children:S})]})}})}):v.jsx(ys,{text:"No console entries"});function X_(n){if(n.length===1)return $0(n[0].preview);const e=typeof n[0].value=="string"&&n[0].value.includes("%"),i=e?n[0].value:"",r=e?n.slice(1):n;let l=0;const o=/%([%sdifoOc])/g;let u;const f=[];let d=[];f.push(v.jsx("span",{children:d},f.length+1));let g=0;for(;(u=o.exec(i))!==null;){const b=i.substring(g,u.index);d.push(v.jsx("span",{children:b},d.length+1)),g=u.index+2;const m=u[0][1];if(m==="%")d.push(v.jsx("span",{children:"%"},d.length+1));else if(m==="s"||m==="o"||m==="O"||m==="d"||m==="i"||m==="f"){const S=r[l++],w={};typeof(S==null?void 0:S.value)!="string"&&(w.color="var(--vscode-debugTokenExpression-number)"),d.push(v.jsx("span",{style:w,children:(S==null?void 0:S.preview)||""},d.length+1))}else if(m==="c"){d=[];const S=r[l++],w=S?Y_(S.preview):{};f.push(v.jsx("span",{style:w,children:d},f.length+1))}}for(gd[1].toUpperCase());e[f]=u}return e}catch{return{}}}function F_(n){return["background","border","color","font","line","margin","padding","text"].some(i=>n.startsWith(i))}const id=({noShadow:n,children:e,noMinHeight:i,className:r,sidebarBackground:l,onClick:o})=>v.jsx("div",{className:st("toolbar",n&&"no-shadow",i&&"no-min-height",r,l&&"toolbar-sidebar-background"),onClick:o,children:e}),Mh=({tabs:n,selectedTab:e,setSelectedTab:i,leftToolbar:r,rightToolbar:l,dataTestId:o,mode:u})=>{const f=R.useId();return e||(e=n[0].id),u||(u="default"),v.jsx("div",{className:"tabbed-pane","data-testid":o,children:v.jsxs("div",{className:"vbox",children:[v.jsxs(id,{children:[r&&v.jsxs("div",{style:{flex:"none",display:"flex",margin:"0 4px",alignItems:"center"},children:[...r]}),u==="default"&&v.jsx("div",{style:{flex:"auto",display:"flex",height:"100%",overflow:"hidden"},role:"tablist",children:[...n.map(d=>v.jsx(I0,{id:d.id,ariaControls:`${f}-${d.id}`,title:d.title,count:d.count,errorCount:d.errorCount,selected:e===d.id,onSelect:i},d.id))]}),u==="select"&&v.jsx("div",{style:{flex:"auto",display:"flex",height:"100%",overflow:"hidden"},role:"tablist",children:v.jsx("select",{style:{width:"100%",background:"none",cursor:"pointer"},value:e,onChange:d=>{i==null||i(n[d.currentTarget.selectedIndex].id)},children:n.map(d=>{let g="";return d.count&&(g=` (${d.count})`),d.errorCount&&(g=` (${d.errorCount})`),v.jsxs("option",{value:d.id,role:"tab","aria-controls":`${f}-${d.id}`,children:[d.title,g]},d.id)})})}),l&&v.jsxs("div",{style:{flex:"none",display:"flex",alignItems:"center"},children:[...l]})]}),n.map(d=>{const g="tab-content tab-"+d.id;if(d.component)return v.jsx("div",{id:`${f}-${d.id}`,role:"tabpanel","aria-label":d.title,className:g,style:{display:e===d.id?"inherit":"none"},children:d.component},d.id);if(e===d.id)return v.jsx("div",{id:`${f}-${d.id}`,role:"tabpanel","aria-label":d.title,className:g,children:d.render()},d.id)})]})})},I0=({id:n,title:e,count:i,errorCount:r,selected:l,onSelect:o,ariaControls:u})=>v.jsxs("div",{className:st("tabbed-pane-tab",l&&"selected"),onClick:()=>o==null?void 0:o(n),role:"tab",title:e,"aria-controls":u,"aria-selected":l,children:[v.jsx("div",{className:"tabbed-pane-tab-label",children:e}),!!i&&v.jsx("div",{className:"tabbed-pane-tab-counter",children:i}),!!r&&v.jsx("div",{className:"tabbed-pane-tab-counter error",children:r})]});async function Q_(n,e){const i=navigator.platform.includes("Win")?"win":"unix";let r=[];const l=new Set(["accept-encoding","host","method","path","scheme","version","authority","protocol"]);function o(S){return'^"'+S.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/[^a-zA-Z0-9\s_\-:=+~'\/.',?;()*`]/g,"^$&").replace(/%(?=[a-zA-Z0-9_])/g,"%^").replace(/[^ -~\r\n]/g," ").replace(/\r?\n|\r/g,`^ - -`)+'^"'}function u(S){function w(T){let _=T.charCodeAt(0).toString(16);for(;_.length<4;)_="0"+_;return"\\u"+_}return/[\0-\x1F\x7F-\x9F!]|\'/.test(S)?"$'"+S.replace(/\\/g,"\\\\").replace(/\'/g,"\\'").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\0-\x1F\x7F-\x9F!]/g,w)+"'":"'"+S+"'"}const f=i==="win"?o:u;r.push(f(e.request.url).replace(/[[{}\]]/g,"\\$&"));let d="GET";const g=[],b=await V0(n,e);b&&(g.push("--data-raw "+f(b)),l.add("content-length"),d="POST"),e.request.method!==d&&r.push("-X "+f(e.request.method));const m=e.request.headers;for(let S=0;S=3?i==="win"?` ^ - `:` \\ - `:" ")}async function P_(n,e,i=0){const r=new Set(["method","path","scheme","version","accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","date","dnt","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","via","user-agent"]),l=new Set(["cookie","authorization"]),o=JSON.stringify(e.request.url),u=e.request.headers,f=u.reduce((x,_)=>{const A=_.name;return!r.has(A.toLowerCase())&&!A.includes(":")&&x.append(A,_.value),x},new Headers),d={};for(const x of f)d[x[0]]=x[1];const g=e.request.cookies.length||u.some(({name:x})=>l.has(x.toLowerCase()))?"include":"omit",b=u.find(({name:x})=>x.toLowerCase()==="referer"),m=b?b.value:void 0,S=await V0(n,e),w={headers:Object.keys(d).length?d:void 0,referrer:m,body:S,method:e.request.method,mode:"cors"};if(i===1){const x=u.find(A=>A.name.toLowerCase()==="cookie"),_={};delete w.mode,x&&(_.cookie=x.value),m&&(delete w.referrer,_.Referer=m),Object.keys(_).length&&(w.headers={...d,..._})}else w.credentials=g;const T=JSON.stringify(w,null,2);return`fetch(${o}, ${T});`}async function V0(n,e){var i,r;return n&&((i=e.request.postData)!=null&&i._sha1)?await fetch(n.createRelativeUrl(`sha1/${e.request.postData._sha1}`)).then(l=>l.text()):(r=e.request.postData)==null?void 0:r.text}class J_{generatePlaywrightRequestCall(e,i){let r=e.method.toLowerCase();const l=new URL(e.url),o=`${l.origin}${l.pathname}`,u={};["delete","get","head","post","put","patch"].includes(r)||(u.method=r,r="fetch"),l.searchParams.size&&(u.params=Object.fromEntries(l.searchParams.entries())),i&&(u.data=i),e.headers.length&&(u.headers=Object.fromEntries(e.headers.map(g=>[g.name,g.value])));const f=[`'${o}'`];return Object.keys(u).length>0&&f.push(this.prettyPrintObject(u)),`await page.request.${r}(${f.join(", ")});`}prettyPrintObject(e,i=2,r=0){if(e===null)return"null";if(e===void 0)return"undefined";if(typeof e!="object")return typeof e=="string"?this.stringLiteral(e):String(e);if(Array.isArray(e)){if(e.length===0)return"[]";const f=" ".repeat(r*i),d=" ".repeat((r+1)*i);return`[ -${e.map(b=>`${d}${this.prettyPrintObject(b,i,r+1)}`).join(`, -`)} -${f}]`}if(Object.keys(e).length===0)return"{}";const l=" ".repeat(r*i),o=" ".repeat((r+1)*i);return`{ -${Object.entries(e).map(([f,d])=>{const g=this.prettyPrintObject(d,i,r+1),b=/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(f)?f:this.stringLiteral(f);return`${o}${b}: ${g}`}).join(`, -`)} -${l}}`}stringLiteral(e){return e=e.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),e.includes(` -`)||e.includes("\r")||e.includes(" ")?"`"+e+"`":`'${e}'`}}class Z_{generatePlaywrightRequestCall(e,i){const r=new URL(e.url),o=[`"${`${r.origin}${r.pathname}`}"`];let u=e.method.toLowerCase();["delete","get","head","post","put","patch"].includes(u)||(o.push(`method="${u}"`),u="fetch"),r.searchParams.size&&o.push(`params=${this.prettyPrintObject(Object.fromEntries(r.searchParams.entries()))}`),i&&o.push(`data=${this.prettyPrintObject(i)}`),e.headers.length&&o.push(`headers=${this.prettyPrintObject(Object.fromEntries(e.headers.map(d=>[d.name,d.value])))}`);const f=o.length===1?o[0]:` -${o.map(d=>this.indent(d,2)).join(`, -`)} -`;return`await page.request.${u}(${f})`}indent(e,i){return e.split(` -`).map(r=>" ".repeat(i)+r).join(` -`)}prettyPrintObject(e,i=2,r=0){if(e===null||e===void 0)return"None";if(typeof e!="object")return typeof e=="string"?this.stringLiteral(e):typeof e=="boolean"?e?"True":"False":String(e);if(Array.isArray(e)){if(e.length===0)return"[]";const f=" ".repeat(r*i),d=" ".repeat((r+1)*i);return`[ -${e.map(b=>`${d}${this.prettyPrintObject(b,i,r+1)}`).join(`, -`)} -${f}]`}if(Object.keys(e).length===0)return"{}";const l=" ".repeat(r*i),o=" ".repeat((r+1)*i);return`{ -${Object.entries(e).map(([f,d])=>{const g=this.prettyPrintObject(d,i,r+1);return`${o}${this.stringLiteral(f)}: ${g}`}).join(`, -`)} -${l}}`}stringLiteral(e){return JSON.stringify(e)}}class W_{generatePlaywrightRequestCall(e,i){const r=new URL(e.url),l=`${r.origin}${r.pathname}`,o={},u=[];let f=e.method.toLowerCase();["delete","get","head","post","put","patch"].includes(f)||(o.Method=f,f="fetch"),r.searchParams.size&&(o.Params=Object.fromEntries(r.searchParams.entries())),i&&(o.Data=i),e.headers.length&&(o.Headers=Object.fromEntries(e.headers.map(b=>[b.name,b.value])));const d=[`"${l}"`];return Object.keys(o).length>0&&d.push(this.prettyPrintObject(o)),`${u.join(` -`)}${u.length?` -`:""}await request.${this.toFunctionName(f)}(${d.join(", ")});`}toFunctionName(e){return e[0].toUpperCase()+e.slice(1)+"Async"}prettyPrintObject(e,i=2,r=0){if(e===null||e===void 0)return"null";if(typeof e!="object")return typeof e=="string"?this.stringLiteral(e):typeof e=="boolean"?e?"true":"false":String(e);if(Array.isArray(e)){if(e.length===0)return"new object[] {}";const f=" ".repeat(r*i),d=" ".repeat((r+1)*i);return`new object[] { -${e.map(b=>`${d}${this.prettyPrintObject(b,i,r+1)}`).join(`, -`)} -${f}}`}if(Object.keys(e).length===0)return"new {}";const l=" ".repeat(r*i),o=" ".repeat((r+1)*i);return`new() { -${Object.entries(e).map(([f,d])=>{const g=this.prettyPrintObject(d,i,r+1),b=r===0?f:`[${this.stringLiteral(f)}]`;return`${o}${b} = ${g}`}).join(`, -`)} -${l}}`}stringLiteral(e){return JSON.stringify(e)}}class eE{generatePlaywrightRequestCall(e,i){const r=new URL(e.url),l=[`"${r.origin}${r.pathname}"`],o=[];let u=e.method.toLowerCase();["delete","get","head","post","put","patch"].includes(u)||(o.push(`setMethod("${u}")`),u="fetch");for(const[f,d]of r.searchParams)o.push(`setQueryParam(${this.stringLiteral(f)}, ${this.stringLiteral(d)})`);i&&o.push(`setData(${this.stringLiteral(i)})`);for(const f of e.headers)o.push(`setHeader(${this.stringLiteral(f.name)}, ${this.stringLiteral(f.value)})`);return o.length>0&&l.push(`RequestOptions.create() - .${o.join(` - .`)} -`),`request.${u}(${l.join(", ")});`}stringLiteral(e){return JSON.stringify(e)}}function tE(n){if(n==="javascript")return new J_;if(n==="python")return new Z_;if(n==="csharp")return new W_;if(n==="java")return new eE;throw new Error("Unsupported language: "+n)}const nE=({resource:n,sdkLanguage:e,startTimeOffset:i,onClose:r})=>{const[l,o]=R.useState("headers"),u=si(),f=Yh(async()=>{if(u&&n.request.postData){const d=n.request.headers.find(b=>b.name.toLowerCase()==="content-type"),g=d?d.value:"";if(n.request.postData._sha1){const b=await fetch(u.createRelativeUrl(`sha1/${n.request.postData._sha1}`));return{text:Oh(await b.text(),g),mimeType:g}}else return{text:Oh(n.request.postData.text,g),mimeType:g}}else return null},[n],null);return v.jsx(Mh,{leftToolbar:[v.jsx(ut,{icon:"close",title:"Close",onClick:r},"close")],rightToolbar:[v.jsx(iE,{requestBody:f,resource:n,sdkLanguage:e},"dropdown")],tabs:[{id:"headers",title:"Headers",render:()=>v.jsx(sE,{resource:n,startTimeOffset:i})},{id:"payload",title:"Payload",render:()=>v.jsx(rE,{resource:n,requestBody:f})},{id:"response",title:"Response",render:()=>v.jsx(aE,{resource:n})}],selectedTab:l,setSelectedTab:o})},iE=({resource:n,sdkLanguage:e,requestBody:i})=>{const r=si(),l=v.jsxs(v.Fragment,{children:[v.jsx("span",{className:"codicon codicon-check",style:{marginRight:"5px"}})," Copied "]}),o=async()=>tE(e).generatePlaywrightRequestCall(n.request,i==null?void 0:i.text);return v.jsxs("div",{className:"copy-request-dropdown",children:[v.jsxs(ut,{className:"copy-request-dropdown-toggle",children:[v.jsx("span",{className:"codicon codicon-copy",style:{marginRight:"5px"}}),"Copy request",v.jsx("span",{className:"codicon codicon-chevron-down",style:{marginLeft:"5px"}})]}),v.jsxs("div",{className:"copy-request-dropdown-menu",children:[v.jsx(Yo,{description:"Copy as cURL",copiedDescription:l,value:()=>Q_(r,n)}),v.jsx(Yo,{description:"Copy as Fetch",copiedDescription:l,value:()=>P_(r,n)}),v.jsx(Yo,{description:"Copy as Playwright",copiedDescription:l,value:o})]})]})},Ya=({title:n,data:e,showCount:i,children:r,className:l})=>{const[o,u]=pn(`trace-viewer-network-details-${n.replaceAll(" ","-")}`,!0);return v.jsxs(H0,{expanded:o,setExpanded:u,expandOnTitleClick:!0,title:v.jsxs("span",{className:"network-request-details-header",children:[n,i&&v.jsxs("span",{className:"network-request-details-header-count",children:[" × ",(e==null?void 0:e.length)??0]})]}),className:l,children:[e&&v.jsx("table",{className:"network-request-details-table",children:v.jsx("tbody",{children:e.map(({name:f,value:d},g)=>d!==null&&v.jsxs("tr",{children:[v.jsx("td",{children:f}),v.jsx("td",{children:d})]},g))})}),r]})},sE=({resource:n,startTimeOffset:e})=>{const i=R.useMemo(()=>Object.entries({URL:n.request.url,Method:n.request.method,"Status Code":n.response.status!==-1&&v.jsxs("span",{className:oE(n.response.status),children:[" ",n.response.status," ",n.response.statusText]}),Start:bt(e),Duration:bt(n.time)}).map(([r,l])=>({name:r,value:l})),[n,e]);return v.jsxs("div",{className:"vbox network-request-details-tab",children:[v.jsx(Ya,{title:"General",data:i}),v.jsx(Ya,{title:"Request Headers",showCount:!0,data:n.request.headers}),v.jsx(Ya,{title:"Response Headers",showCount:!0,data:n.response.headers})]})},rE=({resource:n,requestBody:e})=>v.jsxs("div",{className:"vbox network-request-details-tab",children:[n.request.queryString.length===0&&!e&&v.jsx("em",{className:"network-request-no-payload",children:"No payload for this request."}),n.request.queryString.length>0&&v.jsx(Ya,{title:"Query String Parameters",showCount:!0,data:n.request.queryString}),e&&v.jsx(Ya,{title:"Request Body",className:"network-request-request-body",children:v.jsx(Er,{text:e.text,mimeType:e.mimeType,readOnly:!0,lineNumbers:!0})})]}),aE=({resource:n})=>{const e=si(),[i,r]=R.useState(null);return R.useEffect(()=>{(async()=>{if(e&&n.response.content._sha1){const o=n.response.content.mimeType.includes("image"),u=n.response.content.mimeType.includes("font"),f=await fetch(e.createRelativeUrl(`sha1/${n.response.content._sha1}`));if(o){const d=await f.blob(),g=new FileReader,b=new Promise(m=>g.onload=m);g.readAsDataURL(d),r({dataUrl:(await b).target.result})}else if(u){const d=await f.arrayBuffer();r({font:d})}else{const d=Oh(await f.text(),n.response.content.mimeType);r({text:d,mimeType:n.response.content.mimeType})}}else r(null)})()},[n,e]),v.jsxs("div",{className:"vbox network-request-details-tab",children:[!n.response.content._sha1&&v.jsx("div",{children:"Response body is not available for this request."}),i&&i.font&&v.jsx(lE,{font:i.font}),i&&i.dataUrl&&v.jsx("div",{children:v.jsx("img",{draggable:"false",src:i.dataUrl})}),i&&i.text&&v.jsx(Er,{text:i.text,mimeType:i.mimeType,readOnly:!0,lineNumbers:!0})]})},lE=({font:n})=>{const[e,i]=R.useState(!1);return R.useEffect(()=>{let r;try{r=new FontFace("font-preview",n),r.status==="loaded"&&document.fonts.add(r),r.status==="error"&&i(!0)}catch{i(!0)}return()=>{document.fonts.delete(r)}},[n]),e?v.jsx("div",{className:"network-font-preview-error",children:"Could not load font preview"}):v.jsxs("div",{className:"network-font-preview",children:["ABCDEFGHIJKLM",v.jsx("br",{}),"NOPQRSTUVWXYZ",v.jsx("br",{}),"abcdefghijklm",v.jsx("br",{}),"nopqrstuvwxyz",v.jsx("br",{}),"1234567890"]})};function oE(n){return n<300||n===304?"green-circle":n<400?"yellow-circle":"red-circle"}const cE=/<[^>]+>[^<]*<\//;function uE(n,e=" "){let i=0;const r=[],l=n.replace(/>\s* -<`).split(` -`);for(const o of l){const u=o.trim();u&&(u.startsWith("")||u.startsWith("";if(j_(e))try{return JSON.stringify(JSON.parse(i),null,2)}catch{return i}if(L_(e))try{return uE(i)}catch{return i}return e.includes("application/x-www-form-urlencoded")?decodeURIComponent(i):i}function fE(n){const[e,i]=R.useState([]);R.useEffect(()=>{const o=[];for(let u=0;u{var u,f;(f=n.setSorting)==null||f.call(n,{by:o,negate:((u=n.sorting)==null?void 0:u.by)===o?!n.sorting.negate:!1})},[n]);return v.jsxs("div",{className:`grid-view ${n.name}-grid-view`,children:[v.jsx(U0,{orientation:"horizontal",offsets:e,setOffsets:r,resizerColor:"var(--vscode-panel-border)",resizerWidth:1,minColumnWidth:25}),v.jsxs("div",{className:"vbox",children:[v.jsx("div",{className:"grid-view-header",children:n.columns.map((o,u)=>v.jsxs("div",{className:"grid-view-header-cell "+hE(o,n.sorting),style:{width:un.setSorting&&l(o),children:[v.jsx("span",{className:"grid-view-header-cell-title",children:n.columnTitle(o)}),v.jsx("span",{className:"codicon codicon-triangle-up"}),v.jsx("span",{className:"codicon codicon-triangle-down"})]},n.columnTitle(o)))}),v.jsx(yc,{name:n.name,items:n.items,ariaLabel:n.ariaLabel,id:n.id,render:(o,u)=>v.jsx(v.Fragment,{children:n.columns.map((f,d)=>{const{body:g,title:b}=n.render(o,f,u);return v.jsx("div",{className:`grid-view-cell grid-view-column-${String(f)}`,title:b,style:{width:dv.jsxs("div",{className:"network-filters",children:[v.jsx("input",{type:"search",placeholder:"Filter network",spellCheck:!1,value:n.searchValue,onChange:i=>e({...n,searchValue:i.target.value})}),v.jsxs("div",{className:"network-filters-resource-types",role:"tablist","aria-multiselectable":"true",children:[v.jsx("div",{title:"All",onClick:()=>e({...n,resourceTypes:new Set}),className:`network-filters-resource-type ${n.resourceTypes.size===0?"selected":""}`,children:"All"}),dE.map(i=>v.jsx("div",{title:i,onClick:r=>{let l;r.ctrlKey||r.metaKey?l=n.resourceTypes.symmetricDifference(new Set([i])):l=new Set([i]),e({...n,resourceTypes:l})},className:`network-filters-resource-type ${n.resourceTypes.has(i)?"selected":""}`,role:"tab","aria-selected":n.resourceTypes.has(i),children:i},i))]})]}),mE=fE;function yE(n,e){const i=R.useMemo(()=>((n==null?void 0:n.resources)||[]).filter(u=>e?!!u._monotonicTime&&u._monotonicTime>=e.minimum&&u._monotonicTime<=e.maximum:!0),[n,e]),r=R.useMemo(()=>new _E(n),[n]);return{resources:i,contextIdMap:r}}const bE=({boundaries:n,networkModel:e,onResourceHovered:i,sdkLanguage:r})=>{const[l,o]=R.useState(void 0),[u,f]=R.useState(void 0),[d,g]=R.useState(pE),{renderedEntries:b}=R.useMemo(()=>{const _=e.resources.map(A=>EE(A,n,e.contextIdMap)).filter(kE(d));return l&&AE(_,l),{renderedEntries:_}},[e.resources,e.contextIdMap,d,l,n]),m=R.useMemo(()=>u?b.find(_=>_.resource.id===u):void 0,[u,b]),[S,w]=R.useState(()=>new Map(G0().map(_=>[_,SE(_)]))),T=R.useCallback(_=>{g(_),f(void 0)},[]);if(!e.resources.length)return v.jsx(ys,{text:"No network calls"});const x=v.jsx(mE,{name:"network",ariaLabel:"Network requests",items:b,selectedItem:m,onSelected:_=>f(_.resource.id),onHighlighted:_=>i==null?void 0:i(_==null?void 0:_.resource.id),columns:wE(!!m,b),columnTitle:vE,columnWidths:S,setColumnWidths:w,isError:_=>_.status.code>=400||_.status.code===-1,isInfo:_=>!!_.route,render:(_,A)=>xE(_,A),sorting:l,setSorting:o});return v.jsxs(v.Fragment,{children:[v.jsx(gE,{filterState:d,onFilterStateChange:T}),!m&&x,m&&v.jsx(nc,{sidebarSize:S.get("name"),sidebarIsFirst:!0,orientation:"horizontal",settingName:"networkResourceDetails",main:v.jsx(nE,{resource:m.resource,sdkLanguage:r,startTimeOffset:m.start,onClose:()=>f(void 0)}),sidebar:x})]})},vE=n=>n==="contextId"?"Source":n==="name"?"Name":n==="method"?"Method":n==="status"?"Status":n==="contentType"?"Content Type":n==="duration"?"Duration":n==="size"?"Size":n==="start"?"Start":n==="route"?"Route":"",SE=n=>n==="name"?200:n==="method"||n==="status"?60:n==="contentType"?200:n==="contextId"?60:100;function wE(n,e){if(n){const r=["name"];return db(e)&&r.unshift("contextId"),r}let i=G0();return db(e)||(i=i.filter(r=>r!=="contextId")),i}function G0(){return["contextId","name","method","status","contentType","duration","size","start","route"]}const xE=(n,e)=>e==="contextId"?{body:n.contextId,title:n.name.url}:e==="name"?{body:n.name.name,title:n.name.url}:e==="method"?{body:n.method}:e==="status"?{body:n.status.code>0?n.status.code:"",title:n.status.text}:e==="contentType"?{body:n.contentType}:e==="duration"?{body:bt(n.duration)}:e==="size"?{body:Lx(n.size)}:e==="start"?{body:bt(n.start)}:e==="route"?{body:n.route}:{body:""};class _E{constructor(e){this._pagerefToShortId=new Map,this._contextToId=new Map,this._lastPageId=0,this._lastApiRequestContextId=0}contextId(e){return e.pageref?this._pageId(e.pageref):e._apiRequest?this._apiRequestContextId(e):""}_pageId(e){let i=this._pagerefToShortId.get(e);return i||(++this._lastPageId,i="page#"+this._lastPageId,this._pagerefToShortId.set(e,i)),i}_apiRequestContextId(e){const i=c0(e);if(!i)return"";let r=this._contextToId.get(i);return r||(++this._lastApiRequestContextId,r="api#"+this._lastApiRequestContextId,this._contextToId.set(i,r)),r}}function db(n){const e=new Set;for(const i of n)if(e.add(i.contextId),e.size>1)return!0;return!1}const EE=(n,e,i)=>{const r=TE(n);let l;try{const f=new URL(n.request.url);l=f.pathname.substring(f.pathname.lastIndexOf("/")+1),l||(l=f.host),f.search&&(l+=f.search)}catch{l=n.request.url}let o=n.response.content.mimeType;const u=o.match(/^(.*);\s*charset=.*$/);return u&&(o=u[1]),{name:{name:l,url:n.request.url},method:n.request.method,status:{code:n.response.status,text:n.response.statusText},contentType:o,duration:n.time,size:n.response._transferSize>0?n.response._transferSize:n.response.bodySize,start:n._monotonicTime-e.minimum,route:r,resource:n,contextId:i.contextId(n)}};function TE(n){return n._wasAborted?"aborted":n._wasContinued?"continued":n._wasFulfilled?"fulfilled":n._apiRequest?"api":""}function AE(n,e){const i=CE(e==null?void 0:e.by);i&&n.sort(i),e.negate&&n.reverse()}function CE(n){if(n==="start")return(e,i)=>e.start-i.start;if(n==="duration")return(e,i)=>e.duration-i.duration;if(n==="status")return(e,i)=>e.status.code-i.status.code;if(n==="method")return(e,i)=>{const r=e.method,l=i.method;return r.localeCompare(l)};if(n==="size")return(e,i)=>e.size-i.size;if(n==="contentType")return(e,i)=>e.contentType.localeCompare(i.contentType);if(n==="name")return(e,i)=>e.name.name.localeCompare(i.name.name);if(n==="route")return(e,i)=>e.route.localeCompare(i.route);if(n==="contextId")return(e,i)=>e.contextId.localeCompare(i.contextId)}const NE={Fetch:n=>n==="application/json",HTML:n=>n==="text/html",CSS:n=>n==="text/css",JS:n=>n.includes("javascript"),Font:n=>n.includes("font"),Image:n=>n.includes("image")};function kE({searchValue:n,resourceTypes:e}){return i=>(e.size===0||Array.from(e).some(l=>NE[l](i.contentType)))&&i.name.url.toLowerCase().includes(n.toLowerCase())}function ME(n,e){if(n.role!==e.role||n.name!==e.name||!OE(n,e)||lc(n)!==lc(e))return!1;const i=Object.keys(n.props),r=Object.keys(e.props);return i.length===r.length&&i.every(l=>n.props[l]===e.props[l])}function lc(n){return n.box.cursor==="pointer"}function OE(n,e){return n.active===e.active&&n.checked===e.checked&&n.disabled===e.disabled&&n.expanded===e.expanded&&n.selected===e.selected&&n.level===e.level&&n.pressed===e.pressed}function sd(n,e,i={}){var S;const r=new n.LineCounter,l={keepSourceTokens:!0,lineCounter:r,...i},o=n.parseDocument(e,l),u=[],f=w=>[r.linePos(w[0]),r.linePos(w[1])],d=w=>{u.push({message:w.message,range:[r.linePos(w.pos[0]),r.linePos(w.pos[1])]})},g=(w,T)=>{for(const x of T.items){if(x instanceof n.Scalar&&typeof x.value=="string"){const N=oc.parse(x,l,u);N&&(w.children=w.children||[],w.children.push(N));continue}if(x instanceof n.YAMLMap){b(w,x);continue}u.push({message:"Sequence items should be strings or maps",range:f(x.range||T.range)})}},b=(w,T)=>{for(const x of T.items){if(w.children=w.children||[],!(x.key instanceof n.Scalar&&typeof x.key.value=="string")){u.push({message:"Only string keys are supported",range:f(x.key.range||T.range)});continue}const A=x.key,N=x.value;if(A.value==="text"){if(!(N instanceof n.Scalar&&typeof N.value=="string")){u.push({message:"Text value should be a string",range:f(x.value.range||T.range)});continue}w.children.push({kind:"text",text:ah(N.value)});continue}if(A.value==="/children"){if(!(N instanceof n.Scalar&&typeof N.value=="string")||N.value!=="contain"&&N.value!=="equal"&&N.value!=="deep-equal"){u.push({message:'Strict value should be "contain", "equal" or "deep-equal"',range:f(x.value.range||T.range)});continue}w.containerMode=N.value;continue}if(A.value.startsWith("/")){if(!(N instanceof n.Scalar&&typeof N.value=="string")){u.push({message:"Property value should be a string",range:f(x.value.range||T.range)});continue}w.props=w.props??{},w.props[A.value.slice(1)]=ah(N.value);continue}const $=oc.parse(A,l,u);if(!$)continue;if(N instanceof n.Scalar){const U=typeof N.value;if(U!=="string"&&U!=="number"&&U!=="boolean"){u.push({message:"Node value should be a string or a sequence",range:f(x.value.range||T.range)});continue}w.children.push({...$,children:[{kind:"text",text:ah(String(N.value))}]});continue}if(N instanceof n.YAMLSeq){w.children.push($),g($,N);continue}u.push({message:"Map values should be strings or sequences",range:f(x.value.range||T.range)})}},m={kind:"role",role:"fragment"};return o.errors.forEach(d),u.length?{errors:u,fragment:m}:(o.contents instanceof n.YAMLSeq||u.push({message:'Aria snapshot must be a YAML sequence, elements starting with " -"',range:o.contents?f(o.contents.range):[{line:0,col:0},{line:0,col:0}]}),u.length?{errors:u,fragment:m}:(g(m,o.contents),u.length?{errors:u,fragment:jE}:((S=m.children)==null?void 0:S.length)===1&&(!m.containerMode||m.containerMode==="contain")?{fragment:m.children[0],errors:[]}:{fragment:m,errors:[]}))}const jE={kind:"role",role:"fragment"};function K0(n){return n.replace(/[\u200b\u00ad]/g,"").replace(/[\r\n\s\t]+/g," ").trim()}function ah(n){return{raw:n,normalized:K0(n)}}class oc{static parse(e,i,r){try{return new oc(e.value)._parse()}catch(l){if(l instanceof pb){const o=i.prettyErrors===!1?l.message:l.message+`: - -`+e.value+` -`+" ".repeat(l.pos)+`^ -`;return r.push({message:o,range:[i.lineCounter.linePos(e.range[0]),i.lineCounter.linePos(e.range[0]+l.pos)]}),null}throw l}}constructor(e){this._input=e,this._pos=0,this._length=e.length}_peek(){return this._input[this._pos]||""}_next(){return this._pos=this._length}_isWhitespace(){return!this._eof()&&/\s/.test(this._peek())}_skipWhitespace(){for(;this._isWhitespace();)this._pos++}_readIdentifier(e){this._eof()&&this._throwError(`Unexpected end of input when expecting ${e}`);const i=this._pos;for(;!this._eof()&&/[a-zA-Z]/.test(this._peek());)this._pos++;return this._input.slice(i,this._pos)}_readString(){let e="",i=!1;for(;!this._eof();){const r=this._next();if(i)e+=r,i=!1;else if(r==="\\")i=!0;else{if(r==='"')return e;e+=r}}this._throwError("Unterminated string")}_throwError(e,i=0){throw new pb(e,i||this._pos)}_readRegex(){let e="",i=!1,r=!1;for(;!this._eof();){const l=this._next();if(i)e+=l,i=!1;else if(l==="\\")i=!0,e+=l;else{if(l==="/"&&!r)return{pattern:e};l==="["?(r=!0,e+=l):l==="]"&&r?(e+=l,r=!1):e+=l}}this._throwError("Unterminated regex")}_readStringOrRegex(){const e=this._peek();return e==='"'?(this._next(),K0(this._readString())):e==="/"?(this._next(),this._readRegex()):null}_readAttributes(e){let i=this._pos;for(;this._skipWhitespace(),this._peek()==="[";){this._next(),this._skipWhitespace(),i=this._pos;const r=this._readIdentifier("attribute");this._skipWhitespace();let l="";if(this._peek()==="=")for(this._next(),this._skipWhitespace(),i=this._pos;this._peek()!=="]"&&!this._isWhitespace()&&!this._eof();)l+=this._next();this._skipWhitespace(),this._peek()!=="]"&&this._throwError("Expected ]"),this._next(),this._applyAttribute(e,r,l||"true",i)}}_parse(){this._skipWhitespace();const e=this._readIdentifier("role");this._skipWhitespace();const i=this._readStringOrRegex()||"",r={kind:"role",role:e,name:i};return this._readAttributes(r),this._skipWhitespace(),this._eof()||this._throwError("Unexpected input"),r}_applyAttribute(e,i,r,l){if(i==="checked"){this._assert(r==="true"||r==="false"||r==="mixed",'Value of "checked" attribute must be a boolean or "mixed"',l),e.checked=r==="true"?!0:r==="false"?!1:"mixed";return}if(i==="disabled"){this._assert(r==="true"||r==="false",'Value of "disabled" attribute must be a boolean',l),e.disabled=r==="true";return}if(i==="expanded"){this._assert(r==="true"||r==="false",'Value of "expanded" attribute must be a boolean',l),e.expanded=r==="true";return}if(i==="active"){this._assert(r==="true"||r==="false",'Value of "active" attribute must be a boolean',l),e.active=r==="true";return}if(i==="level"){this._assert(!isNaN(Number(r)),'Value of "level" attribute must be a number',l),e.level=Number(r);return}if(i==="pressed"){this._assert(r==="true"||r==="false"||r==="mixed",'Value of "pressed" attribute must be a boolean or "mixed"',l),e.pressed=r==="true"?!0:r==="false"?!1:"mixed";return}if(i==="selected"){this._assert(r==="true"||r==="false",'Value of "selected" attribute must be a boolean',l),e.selected=r==="true";return}this._assert(!1,`Unsupported attribute [${i}]`,l)}_assert(e,i,r){e||this._throwError(i||"Assertion error",r)}}class pb extends Error{constructor(e,i){super(e),this.pos=i}}function LE(n,e){var u,f;function i(d,g,b){let m=1,S=b+m;for(const w of d.children||[])typeof w=="string"?(m++,S++):(m+=i(w,g,S),S+=m);if(!["none","presentation","fragment","iframe","generic"].includes(d.role)&&d.name){let w=g.get(d.role);w||(w=new Map,g.set(d.role,w));const T=w.get(d.name),x=m*100-b;(!T||T.sizeAndPositiong.sizeAndPosition-d.sizeAndPosition),(f=o[0])==null?void 0:f.node}function RE(n){return X0(n)?"'"+n.replace(/'/g,"''")+"'":n}function lh(n){return X0(n)?'"'+n.replace(/[\\"\x00-\x1f\x7f-\x9f]/g,e=>{switch(e){case"\\":return"\\\\";case'"':return'\\"';case"\b":return"\\b";case"\f":return"\\f";case` -`:return"\\n";case"\r":return"\\r";case" ":return"\\t";default:return"\\x"+e.charCodeAt(0).toString(16).padStart(2,"0")}})+'"':n}function X0(n){return!!(n.length===0||/^\s|\s$/.test(n)||/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/.test(n)||/^-/.test(n)||/[\n:](\s|$)/.test(n)||/\s#/.test(n)||/[\n\r]/.test(n)||/^[&*\],?!>|@"'#%]/.test(n)||/[{}`]/.test(n)||/^\[/.test(n)||!isNaN(Number(n))||["y","n","yes","no","true","false","on","off","null"].includes(n.toLowerCase()))}let Y0={};function DE(n){Y0=n}function jh(n,e){for(;e;){if(n.contains(e))return!0;e=Q0(e)}return!1}function xt(n){if(n.parentElement)return n.parentElement;if(n.parentNode&&n.parentNode.nodeType===11&&n.parentNode.host)return n.parentNode.host}function F0(n){let e=n;for(;e.parentNode;)e=e.parentNode;if(e.nodeType===11||e.nodeType===9)return e}function Q0(n){for(;n.parentElement;)n=n.parentElement;return xt(n)}function qa(n,e,i){for(;n;){const r=n.closest(e);if(i&&r!==i&&(r!=null&&r.contains(i)))return;if(r)return r;n=Q0(n)}}function Hi(n,e){const i=e==="::before"?ad:e==="::after"?ld:rd;if(i&&i.has(n))return i.get(n);const r=n.ownerDocument&&n.ownerDocument.defaultView?n.ownerDocument.defaultView.getComputedStyle(n,e):void 0;return i==null||i.set(n,r),r}function P0(n,e){if(e=e??Hi(n),!e)return!0;if(Element.prototype.checkVisibility&&Y0.browserNameForWorkarounds!=="webkit"){if(!n.checkVisibility())return!1}else{const i=n.closest("details,summary");if(i!==n&&(i==null?void 0:i.nodeName)==="DETAILS"&&!i.open)return!1}return e.visibility==="visible"}function cc(n){const e=Hi(n);if(!e)return{visible:!0,inline:!1};const i=e.cursor;if(e.display==="contents"){for(let l=n.firstChild;l;l=l.nextSibling){if(l.nodeType===1&&Di(l))return{visible:!0,inline:!1,cursor:i};if(l.nodeType===3&&J0(l))return{visible:!0,inline:!0,cursor:i}}return{visible:!1,inline:!1,cursor:i}}if(!P0(n,e))return{cursor:i,visible:!1,inline:!1};const r=n.getBoundingClientRect();return{cursor:i,visible:r.width>0&&r.height>0,inline:e.display==="inline"}}function Di(n){return cc(n).visible}function J0(n){const e=n.ownerDocument.createRange();e.selectNode(n);const i=e.getBoundingClientRect();return i.width>0&&i.height>0}function Je(n){const e=n.tagName;return typeof e=="string"?e.toUpperCase():n instanceof HTMLFormElement?"FORM":n.tagName.toUpperCase()}let rd,ad,ld,Z0=0;function od(){++Z0,rd??(rd=new Map),ad??(ad=new Map),ld??(ld=new Map)}function cd(){--Z0||(rd=void 0,ad=void 0,ld=void 0)}function gb(n){return n.hasAttribute("aria-label")||n.hasAttribute("aria-labelledby")}const mb="article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]",zE=[["aria-atomic",void 0],["aria-busy",void 0],["aria-controls",void 0],["aria-current",void 0],["aria-describedby",void 0],["aria-details",void 0],["aria-dropeffect",void 0],["aria-flowto",void 0],["aria-grabbed",void 0],["aria-hidden",void 0],["aria-keyshortcuts",void 0],["aria-label",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-labelledby",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-live",void 0],["aria-owns",void 0],["aria-relevant",void 0],["aria-roledescription",["generic"]]];function W0(n,e){return zE.some(([i,r])=>!(r!=null&&r.includes(e||""))&&n.hasAttribute(i))}function ev(n){return!Number.isNaN(Number(String(n.getAttribute("tabindex"))))}function UE(n){return!hv(n)&&(HE(n)||ev(n))}function HE(n){const e=Je(n);return["BUTTON","DETAILS","SELECT","TEXTAREA"].includes(e)?!0:e==="A"||e==="AREA"?n.hasAttribute("href"):e==="INPUT"?!n.hidden:!1}const oh={A:n=>n.hasAttribute("href")?"link":null,AREA:n=>n.hasAttribute("href")?"link":null,ARTICLE:()=>"article",ASIDE:()=>"complementary",BLOCKQUOTE:()=>"blockquote",BUTTON:()=>"button",CAPTION:()=>"caption",CODE:()=>"code",DATALIST:()=>"listbox",DD:()=>"definition",DEL:()=>"deletion",DETAILS:()=>"group",DFN:()=>"term",DIALOG:()=>"dialog",DT:()=>"term",EM:()=>"emphasis",FIELDSET:()=>"group",FIGURE:()=>"figure",FOOTER:n=>qa(n,mb)?null:"contentinfo",FORM:n=>gb(n)?"form":null,H1:()=>"heading",H2:()=>"heading",H3:()=>"heading",H4:()=>"heading",H5:()=>"heading",H6:()=>"heading",HEADER:n=>qa(n,mb)?null:"banner",HR:()=>"separator",HTML:()=>"document",IMG:n=>n.getAttribute("alt")===""&&!n.getAttribute("title")&&!W0(n)&&!ev(n)?"presentation":"img",INPUT:n=>{const e=n.type.toLowerCase();if(e==="search")return n.hasAttribute("list")?"combobox":"searchbox";if(["email","tel","text","url",""].includes(e)){const i=kr(n,n.getAttribute("list"))[0];return i&&Je(i)==="DATALIST"?"combobox":"textbox"}return e==="hidden"?null:e==="file"?"button":eT[e]||"textbox"},INS:()=>"insertion",LI:()=>"listitem",MAIN:()=>"main",MARK:()=>"mark",MATH:()=>"math",MENU:()=>"list",METER:()=>"meter",NAV:()=>"navigation",OL:()=>"list",OPTGROUP:()=>"group",OPTION:()=>"option",OUTPUT:()=>"status",P:()=>"paragraph",PROGRESS:()=>"progressbar",SEARCH:()=>"search",SECTION:n=>gb(n)?"region":null,SELECT:n=>n.hasAttribute("multiple")||n.size>1?"listbox":"combobox",STRONG:()=>"strong",SUB:()=>"subscript",SUP:()=>"superscript",SVG:()=>"img",TABLE:()=>"table",TBODY:()=>"rowgroup",TD:n=>{const e=qa(n,"table"),i=e?ud(e):"";return i==="grid"||i==="treegrid"?"gridcell":"cell"},TEXTAREA:()=>"textbox",TFOOT:()=>"rowgroup",TH:n=>{const e=n.getAttribute("scope");if(e==="col"||e==="colgroup")return"columnheader";if(e==="row"||e==="rowgroup")return"rowheader";const i=n.nextElementSibling,r=n.previousElementSibling,l=n.parentElement&&Je(n.parentElement)==="TR"?n.parentElement:void 0;if(!i&&!r){if(l){const o=qa(l,"table");if(o&&o.rows.length<=1)return null}return"columnheader"}return yb(i)&&yb(r)?"columnheader":bb(i)||bb(r)?"rowheader":"columnheader"},THEAD:()=>"rowgroup",TIME:()=>"time",TR:()=>"row",UL:()=>"list"};function yb(n){return!!n&&Je(n)==="TH"}function bb(n){var e;return!n||Je(n)!=="TD"?!1:!!((e=n.textContent)!=null&&e.trim()||n.children.length>0)}const BE={DD:["DL","DIV"],DIV:["DL"],DT:["DL","DIV"],LI:["OL","UL"],TBODY:["TABLE"],TD:["TR"],TFOOT:["TABLE"],TH:["TR"],THEAD:["TABLE"],TR:["THEAD","TBODY","TFOOT","TABLE"]};function vb(n){var r;const e=((r=oh[Je(n)])==null?void 0:r.call(oh,n))||"";if(!e)return null;let i=n;for(;i;){const l=xt(i),o=BE[Je(i)];if(!o||!l||!o.includes(Je(l)))break;const u=ud(l);if((u==="none"||u==="presentation")&&!tv(l,u))return u;i=l}return e}const qE=["alert","alertdialog","application","article","banner","blockquote","button","caption","cell","checkbox","code","columnheader","combobox","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","grid","gridcell","group","heading","img","insertion","link","list","listbox","listitem","log","main","mark","marquee","math","meter","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","navigation","none","note","option","paragraph","presentation","progressbar","radio","radiogroup","region","row","rowgroup","rowheader","scrollbar","search","searchbox","separator","slider","spinbutton","status","strong","subscript","superscript","switch","tab","table","tablist","tabpanel","term","textbox","time","timer","toolbar","tooltip","tree","treegrid","treeitem"];function ud(n){return(n.getAttribute("role")||"").split(" ").map(i=>i.trim()).find(i=>qE.includes(i))||null}function tv(n,e){return W0(n,e)||UE(n)}function St(n){const e=ud(n);if(!e)return vb(n);if(e==="none"||e==="presentation"){const i=vb(n);if(tv(n,i))return i}return e}function nv(n){return n===null?void 0:n.toLowerCase()==="true"}function iv(n){return["STYLE","SCRIPT","NOSCRIPT","TEMPLATE"].includes(Je(n))}function dn(n){if(iv(n))return!0;const e=Hi(n),i=n.nodeName==="SLOT";if((e==null?void 0:e.display)==="contents"&&!i){for(let l=n.firstChild;l;l=l.nextSibling)if(l.nodeType===1&&!dn(l)||l.nodeType===3&&J0(l))return!1;return!0}return!(n.nodeName==="OPTION"&&!!n.closest("select"))&&!i&&!P0(n,e)?!0:sv(n)}function sv(n){let e=ji==null?void 0:ji.get(n);if(e===void 0){if(e=!1,n.parentElement&&n.parentElement.shadowRoot&&!n.assignedSlot&&(e=!0),!e){const i=Hi(n);e=!i||i.display==="none"||nv(n.getAttribute("aria-hidden"))===!0}if(!e){const i=xt(n);i&&(e=sv(i))}ji==null||ji.set(n,e)}return e}function kr(n,e){if(!e)return[];const i=F0(n);if(!i)return[];try{const r=e.split(" ").filter(o=>!!o),l=[];for(const o of r){const u=i.querySelector("#"+CSS.escape(o));u&&!l.includes(u)&&l.push(u)}return l}catch{return[]}}function ei(n){return n.trim()}function Fa(n){return n.split(" ").map(e=>e.replace(/\r\n/g,` -`).replace(/[\u200b\u00ad]/g,"").replace(/\s\s*/g," ")).join(" ").trim()}function Sb(n,e){const i=[...n.querySelectorAll(e)];for(const r of kr(n,n.getAttribute("aria-owns")))r.matches(e)&&i.push(r),i.push(...r.querySelectorAll(e));return i}function Qa(n,e){const i=e==="::before"?xd:e==="::after"?_d:wd;if(i!=null&&i.has(n))return i==null?void 0:i.get(n);const r=Hi(n,e);let l;if(r){const o=r.content;o&&o!=="none"&&o!=="normal"&&r.display!=="none"&&r.visibility!=="hidden"&&(l=$E(n,o,!!e))}return e&&l!==void 0&&((r==null?void 0:r.display)||"inline")!=="inline"&&(l=" "+l+" "),i&&i.set(n,l),l}function $E(n,e,i){if(!(!e||e==="none"||e==="normal"))try{let r=u0(e).filter(f=>!(f instanceof ic));const l=r.findIndex(f=>f instanceof mt&&f.value==="/");if(l!==-1)r=r.slice(l+1);else if(!i)return;const o=[];let u=0;for(;uxn(o,{includeHidden:e,visitedElements:new Set,embeddedInDescribedBy:{element:o,hidden:dn(o)}})).join(" "))}else n.hasAttribute("aria-description")?r=Fa(n.getAttribute("aria-description")||""):r=Fa(n.getAttribute("title")||"");i==null||i.set(n,r)}return r}function VE(n){const e=n.getAttribute("aria-invalid");return!e||e.trim()===""||e.toLocaleLowerCase()==="false"?"false":e==="true"||e==="grammar"||e==="spelling"?e:"true"}function GE(n){if("validity"in n){const e=n.validity;return(e==null?void 0:e.valid)===!1}return!1}function KE(n){const e=gr;let i=gr==null?void 0:gr.get(n);if(i===void 0){i="";const r=VE(n)!=="false",l=GE(n);if(r||l){const o=n.getAttribute("aria-errormessage");i=kr(n,o).map(d=>Fa(xn(d,{visitedElements:new Set,embeddedInDescribedBy:{element:d,hidden:dn(d)}}))).join(" ").trim()}e==null||e.set(n,i)}return i}function xn(n,e){var d,g,b,m;if(e.visitedElements.has(n))return"";const i={...e,embeddedInTargetElement:e.embeddedInTargetElement==="self"?"descendant":e.embeddedInTargetElement};if(!e.includeHidden){const S=!!((d=e.embeddedInLabelledBy)!=null&&d.hidden)||!!((g=e.embeddedInDescribedBy)!=null&&g.hidden)||!!((b=e.embeddedInNativeTextAlternative)!=null&&b.hidden)||!!((m=e.embeddedInLabel)!=null&&m.hidden);if(iv(n)||!S&&dn(n))return e.visitedElements.add(n),""}const r=rv(n);if(!e.embeddedInLabelledBy){const S=(r||[]).map(w=>xn(w,{...e,embeddedInLabelledBy:{element:w,hidden:dn(w)},embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0,embeddedInLabel:void 0,embeddedInNativeTextAlternative:void 0})).join(" ");if(S)return S}const l=St(n)||"",o=Je(n);if(e.embeddedInLabel||e.embeddedInLabelledBy||e.embeddedInTargetElement==="descendant"){const S=[...n.labels||[]].includes(n),w=(r||[]).includes(n);if(!S&&!w){if(l==="textbox")return e.visitedElements.add(n),o==="INPUT"||o==="TEXTAREA"?n.value:n.textContent||"";if(["combobox","listbox"].includes(l)){e.visitedElements.add(n);let T;if(o==="SELECT")T=[...n.selectedOptions],!T.length&&n.options.length&&T.push(n.options[0]);else{const x=l==="combobox"?Sb(n,"*").find(_=>St(_)==="listbox"):n;T=x?Sb(x,'[aria-selected="true"]').filter(_=>St(_)==="option"):[]}return!T.length&&o==="INPUT"?n.value:T.map(x=>xn(x,i)).join(" ")}if(["progressbar","scrollbar","slider","spinbutton","meter"].includes(l))return e.visitedElements.add(n),n.hasAttribute("aria-valuetext")?n.getAttribute("aria-valuetext")||"":n.hasAttribute("aria-valuenow")?n.getAttribute("aria-valuenow")||"":n.getAttribute("value")||"";if(["menu"].includes(l))return e.visitedElements.add(n),""}}const u=n.getAttribute("aria-label")||"";if(ei(u))return e.visitedElements.add(n),u;if(!["presentation","none"].includes(l)){if(o==="INPUT"&&["button","submit","reset"].includes(n.type)){e.visitedElements.add(n);const S=n.value||"";return ei(S)?S:n.type==="submit"?"Submit":n.type==="reset"?"Reset":n.getAttribute("title")||""}if(o==="INPUT"&&n.type==="file"){e.visitedElements.add(n);const S=n.labels||[];return S.length&&!e.embeddedInLabelledBy?La(S,e):"Choose File"}if(o==="INPUT"&&n.type==="image"){e.visitedElements.add(n);const S=n.labels||[];if(S.length&&!e.embeddedInLabelledBy)return La(S,e);const w=n.getAttribute("alt")||"";if(ei(w))return w;const T=n.getAttribute("title")||"";return ei(T)?T:"Submit"}if(!r&&o==="BUTTON"){e.visitedElements.add(n);const S=n.labels||[];if(S.length)return La(S,e)}if(!r&&o==="OUTPUT"){e.visitedElements.add(n);const S=n.labels||[];return S.length?La(S,e):n.getAttribute("title")||""}if(!r&&(o==="TEXTAREA"||o==="SELECT"||o==="INPUT")){e.visitedElements.add(n);const S=n.labels||[];if(S.length)return La(S,e);const w=o==="INPUT"&&["text","password","search","tel","email","url"].includes(n.type)||o==="TEXTAREA",T=n.getAttribute("placeholder")||"",x=n.getAttribute("title")||"";return!w||x?x:T}if(!r&&o==="FIELDSET"){e.visitedElements.add(n);for(let w=n.firstElementChild;w;w=w.nextElementSibling)if(Je(w)==="LEGEND")return xn(w,{...i,embeddedInNativeTextAlternative:{element:w,hidden:dn(w)}});return n.getAttribute("title")||""}if(!r&&o==="FIGURE"){e.visitedElements.add(n);for(let w=n.firstElementChild;w;w=w.nextElementSibling)if(Je(w)==="FIGCAPTION")return xn(w,{...i,embeddedInNativeTextAlternative:{element:w,hidden:dn(w)}});return n.getAttribute("title")||""}if(o==="IMG"){e.visitedElements.add(n);const S=n.getAttribute("alt")||"";return ei(S)?S:n.getAttribute("title")||""}if(o==="TABLE"){e.visitedElements.add(n);for(let w=n.firstElementChild;w;w=w.nextElementSibling)if(Je(w)==="CAPTION")return xn(w,{...i,embeddedInNativeTextAlternative:{element:w,hidden:dn(w)}});const S=n.getAttribute("summary")||"";if(S)return S}if(o==="AREA"){e.visitedElements.add(n);const S=n.getAttribute("alt")||"";return ei(S)?S:n.getAttribute("title")||""}if(o==="SVG"||n.ownerSVGElement){e.visitedElements.add(n);for(let S=n.firstElementChild;S;S=S.nextElementSibling)if(Je(S)==="TITLE"&&S.ownerSVGElement)return xn(S,{...i,embeddedInLabelledBy:{element:S,hidden:dn(S)}})}if(n.ownerSVGElement&&o==="A"){const S=n.getAttribute("xlink:title")||"";if(ei(S))return e.visitedElements.add(n),S}}const f=o==="SUMMARY"&&!["presentation","none"].includes(l);if(IE(l,e.embeddedInTargetElement==="descendant")||f||e.embeddedInLabelledBy||e.embeddedInDescribedBy||e.embeddedInLabel||e.embeddedInNativeTextAlternative){e.visitedElements.add(n);const S=XE(n,i);if(e.embeddedInTargetElement==="self"?ei(S):S)return S}if(!["presentation","none"].includes(l)||o==="IFRAME"){e.visitedElements.add(n);const S=n.getAttribute("title")||"";if(ei(S))return S}return e.visitedElements.add(n),""}function XE(n,e){const i=[],r=(o,u)=>{var f;if(!(u&&o.assignedSlot))if(o.nodeType===1){const d=((f=Hi(o))==null?void 0:f.display)||"inline";let g=xn(o,e);(d!=="inline"||o.nodeName==="BR")&&(g=" "+g+" "),i.push(g)}else o.nodeType===3&&i.push(o.textContent||"")};i.push(Qa(n,"::before")||"");const l=Qa(n);if(l!==void 0)i.push(l);else{const o=n.nodeName==="SLOT"?n.assignedNodes():[];if(o.length)for(const u of o)r(u,!1);else{for(let u=n.firstChild;u;u=u.nextSibling)r(u,!0);if(n.shadowRoot)for(let u=n.shadowRoot.firstChild;u;u=u.nextSibling)r(u,!0);for(const u of kr(n,n.getAttribute("aria-owns")))r(u,!0)}}return i.push(Qa(n,"::after")||""),i.join("")}const fd=["gridcell","option","row","tab","rowheader","columnheader","treeitem"];function av(n){return Je(n)==="OPTION"?n.selected:fd.includes(St(n)||"")?nv(n.getAttribute("aria-selected"))===!0:!1}const hd=["checkbox","menuitemcheckbox","option","radio","switch","menuitemradio","treeitem"];function lv(n){const e=dd(n,!0);return e==="error"?!1:e}function YE(n){return dd(n,!0)}function FE(n){return dd(n,!1)}function dd(n,e){const i=Je(n);if(e&&i==="INPUT"&&n.indeterminate)return"mixed";if(i==="INPUT"&&["checkbox","radio"].includes(n.type))return n.checked;if(hd.includes(St(n)||"")){const r=n.getAttribute("aria-checked");return r==="true"?!0:e&&r==="mixed"?"mixed":!1}return"error"}const QE=["checkbox","combobox","grid","gridcell","listbox","radiogroup","slider","spinbutton","textbox","columnheader","rowheader","searchbox","switch","treegrid"];function PE(n){const e=Je(n);return["INPUT","TEXTAREA","SELECT"].includes(e)?n.hasAttribute("readonly"):QE.includes(St(n)||"")?n.getAttribute("aria-readonly")==="true":n.isContentEditable?!1:"error"}const pd=["button"];function ov(n){if(pd.includes(St(n)||"")){const e=n.getAttribute("aria-pressed");if(e==="true")return!0;if(e==="mixed")return"mixed"}return!1}const gd=["application","button","checkbox","combobox","gridcell","link","listbox","menuitem","row","rowheader","tab","treeitem","columnheader","menuitemcheckbox","menuitemradio","rowheader","switch"];function cv(n){if(Je(n)==="DETAILS")return n.open;if(gd.includes(St(n)||"")){const e=n.getAttribute("aria-expanded");return e===null?void 0:e==="true"}}const md=["heading","listitem","row","treeitem"];function uv(n){const e={H1:1,H2:2,H3:3,H4:4,H5:5,H6:6}[Je(n)];if(e)return e;if(md.includes(St(n)||"")){const i=n.getAttribute("aria-level"),r=i===null?Number.NaN:Number(i);if(Number.isInteger(r)&&r>=1)return r}return 0}const fv=["application","button","composite","gridcell","group","input","link","menuitem","scrollbar","separator","tab","checkbox","columnheader","combobox","grid","listbox","menu","menubar","menuitemcheckbox","menuitemradio","option","radio","radiogroup","row","rowheader","searchbox","select","slider","spinbutton","switch","tablist","textbox","toolbar","tree","treegrid","treeitem"];function uc(n){return hv(n)||dv(n)}function hv(n){return["BUTTON","INPUT","SELECT","TEXTAREA","OPTION","OPTGROUP"].includes(Je(n))&&(n.hasAttribute("disabled")||JE(n)||ZE(n))}function JE(n){return Je(n)==="OPTION"&&!!n.closest("OPTGROUP[DISABLED]")}function ZE(n){const e=n==null?void 0:n.closest("FIELDSET[DISABLED]");if(!e)return!1;const i=e.querySelector(":scope > LEGEND");return!i||!i.contains(n)}function dv(n,e=!1){if(!n)return!1;if(e||fv.includes(St(n)||"")){const i=(n.getAttribute("aria-disabled")||"").toLowerCase();return i==="true"?!0:i==="false"?!1:dv(xt(n),!0)}return!1}function La(n,e){return[...n].map(i=>xn(i,{...e,embeddedInLabel:{element:i,hidden:dn(i)},embeddedInNativeTextAlternative:void 0,embeddedInLabelledBy:void 0,embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0})).filter(i=>!!i).join(" ")}function WE(n){const e=Ed;let i=n,r;const l=[];for(;i;i=xt(i)){const o=e.get(i);if(o!==void 0){r=o;break}l.push(i);const u=Hi(i);if(!u){r=!0;break}const f=u.pointerEvents;if(f){r=f!=="none";break}}r===void 0&&(r=!0);for(const o of l)e.set(o,r);return r}let yd,bd,vd,Sd,gr,ji,wd,xd,_d,Ed,pv=0;function vc(){od(),++pv,yd??(yd=new Map),bd??(bd=new Map),vd??(vd=new Map),Sd??(Sd=new Map),gr??(gr=new Map),ji??(ji=new Map),wd??(wd=new Map),xd??(xd=new Map),_d??(_d=new Map),Ed??(Ed=new Map)}function Sc(){--pv||(yd=void 0,bd=void 0,vd=void 0,Sd=void 0,gr=void 0,ji=void 0,wd=void 0,xd=void 0,_d=void 0,Ed=void 0),cd()}const eT={button:"button",checkbox:"checkbox",image:"button",number:"spinbutton",radio:"radio",range:"slider",reset:"button",submit:"button"};let tT=0;function gv(n){return n.mode==="ai"?{visibility:"ariaOrVisible",refs:"interactable",refPrefix:n.refPrefix,includeGenericRole:!0,renderActive:!n.doNotRenderActive,renderCursorPointer:!0}:n.mode==="autoexpect"?{visibility:"ariaAndVisible",refs:"none"}:n.mode==="codegen"?{visibility:"aria",refs:"none",renderStringsAsRegex:!0}:{visibility:"aria",refs:"none"}}function Pa(n,e){const i=gv(e),r=new Set,l={root:{role:"fragment",name:"",children:[],props:{},box:cc(n),receivesPointerEvents:!0},elements:new Map,refs:new Map,iframeRefs:[]};Lh(l.root,n);const o=(f,d,g)=>{if(r.has(d))return;if(r.add(d),d.nodeType===Node.TEXT_NODE&&d.nodeValue){if(!g)return;const x=d.nodeValue;f.role!=="textbox"&&x&&f.children.push(d.nodeValue||"");return}if(d.nodeType!==Node.ELEMENT_NODE)return;const b=d,m=!dn(b);let S=m;if(i.visibility==="ariaOrVisible"&&(S=m||Di(b)),i.visibility==="ariaAndVisible"&&(S=m&&Di(b)),i.visibility==="aria"&&!S)return;const w=[];if(b.hasAttribute("aria-owns")){const x=b.getAttribute("aria-owns").split(/\s+/);for(const _ of x){const A=n.ownerDocument.getElementById(_);A&&w.push(A)}}const T=S?nT(b,i):null;T&&(T.ref&&(l.elements.set(T.ref,b),l.refs.set(b,T.ref),T.role==="iframe"&&l.iframeRefs.push(T.ref)),f.children.push(T)),u(T||f,b,w,S)};function u(f,d,g,b){var T;const S=(((T=Hi(d))==null?void 0:T.display)||"inline")!=="inline"||d.nodeName==="BR"?" ":"";S&&f.children.push(S),f.children.push(Qa(d,"::before")||"");const w=d.nodeName==="SLOT"?d.assignedNodes():[];if(w.length)for(const x of w)o(f,x,b);else{for(let x=d.firstChild;x;x=x.nextSibling)x.assignedSlot||o(f,x,b);if(d.shadowRoot)for(let x=d.shadowRoot.firstChild;x;x=x.nextSibling)o(f,x,b)}for(const x of g)o(f,x,b);if(f.children.push(Qa(d,"::after")||""),S&&f.children.push(S),f.children.length===1&&f.name===f.children[0]&&(f.children=[]),f.role==="link"&&d.hasAttribute("href")){const x=d.getAttribute("href");f.props.url=x}if(f.role==="textbox"&&d.hasAttribute("placeholder")&&d.getAttribute("placeholder")!==f.name){const x=d.getAttribute("placeholder");f.props.placeholder=x}}vc();try{o(l.root,n,!0)}finally{Sc()}return sT(l.root),iT(l.root),l}function xb(n,e){if(e.refs==="none"||e.refs==="interactable"&&(!n.box.visible||!n.receivesPointerEvents))return;const i=Ad(n);let r=i._ariaRef;(!r||r.role!==n.role||r.name!==n.name)&&(r={role:n.role,name:n.name,ref:(e.refPrefix??"")+"e"+ ++tT},i._ariaRef=r),n.ref=r.ref}function nT(n,e){const i=n.ownerDocument.activeElement===n;if(n.nodeName==="IFRAME"){const g={role:"iframe",name:"",children:[],props:{},box:cc(n),receivesPointerEvents:!0,active:i};return Lh(g,n),xb(g,e),g}const r=e.includeGenericRole?"generic":null,l=St(n)??r;if(!l||l==="presentation"||l==="none")return null;const o=Ot(il(n,!1)||""),u=WE(n),f=cc(n);if(l==="generic"&&f.inline&&n.childNodes.length===1&&n.childNodes[0].nodeType===Node.TEXT_NODE)return null;const d={role:l,name:o,children:[],props:{},box:f,receivesPointerEvents:u,active:i};return Lh(d,n),xb(d,e),hd.includes(l)&&(d.checked=lv(n)),fv.includes(l)&&(d.disabled=uc(n)),gd.includes(l)&&(d.expanded=cv(n)),md.includes(l)&&(d.level=uv(n)),pd.includes(l)&&(d.pressed=ov(n)),fd.includes(l)&&(d.selected=av(n)),(n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement)&&n.type!=="checkbox"&&n.type!=="radio"&&n.type!=="file"&&(d.children=[n.value]),d}function iT(n){const e=i=>{const r=[];for(const o of i.children||[]){if(typeof o=="string"){r.push(o);continue}const u=e(o);r.push(...u)}return i.role==="generic"&&!i.name&&r.length<=1&&r.every(o=>typeof o!="string"&&!!o.ref)?r:(i.children=r,[i])};e(n)}function sT(n){const e=(r,l)=>{if(!r.length)return;const o=Ot(r.join(""));o&&l.push(o),r.length=0},i=r=>{const l=[],o=[];for(const u of r.children||[])typeof u=="string"?o.push(u):(e(o,l),i(u),l.push(u));e(o,l),r.children=l.length?l:[],r.children.length===1&&r.children[0]===r.name&&(r.children=[])};i(n)}function rT(n,e){return e?n?typeof e=="string"?n===e:!!n.match(new RegExp(e.pattern)):!1:!0}function _b(n,e){if(!(e!=null&&e.normalized))return!0;if(!n)return!1;if(n===e.normalized||n===e.raw)return!0;const i=aT(e);return i?!!n.match(i):!1}const ch=Symbol("cachedRegex");function aT(n){if(n[ch]!==void 0)return n[ch];const{raw:e}=n,i=e.startsWith("/")&&e.endsWith("/")&&e.length>1;let r;try{r=i?new RegExp(e.slice(1,-1)):null}catch{r=null}return n[ch]=r,r}function lT(n,e){const i=Pa(n,{mode:"default"});return{matches:mv(i.root,e,!1,!1),received:{raw:Ja(i,{mode:"default"}).text,regex:Ja(i,{mode:"codegen"}).text}}}function oT(n,e){const i=Pa(n,{mode:"default"}).root;return mv(i,e,!0,!1).map(l=>Ad(l))}function Td(n,e,i){var r;return typeof n=="string"&&e.kind==="text"?_b(n,e.text):n===null||typeof n!="object"||e.kind!=="role"||e.role!=="fragment"&&e.role!==n.role||e.checked!==void 0&&e.checked!==n.checked||e.disabled!==void 0&&e.disabled!==n.disabled||e.expanded!==void 0&&e.expanded!==n.expanded||e.level!==void 0&&e.level!==n.level||e.pressed!==void 0&&e.pressed!==n.pressed||e.selected!==void 0&&e.selected!==n.selected||!rT(n.name,e.name)||!_b(n.props.url,(r=e.props)==null?void 0:r.url)?!1:e.containerMode==="contain"?Tb(n.children||[],e.children||[]):e.containerMode==="equal"?Eb(n.children||[],e.children||[],!1):e.containerMode==="deep-equal"||i?Eb(n.children||[],e.children||[],!0):Tb(n.children||[],e.children||[])}function Eb(n,e,i){if(e.length!==n.length)return!1;for(let r=0;rn.length)return!1;const i=n.slice(),r=e.slice();for(const l of r){let o=i.shift();for(;o&&!Td(o,l,!1);)o=i.shift();if(!o)return!1}return!0}function mv(n,e,i,r){const l=[],o=(u,f)=>{if(Td(u,e,r)){const d=typeof u=="string"?f:u;return d&&l.push(d),!i}if(typeof u=="string")return!1;for(const d of u.children||[])if(o(d,u))return!0;return!1};return o(n,null),l}function yv(n,e=new Map){n!=null&&n.ref&&e.set(n.ref,n);for(const i of(n==null?void 0:n.children)||[])typeof i!="string"&&yv(i,e);return e}function cT(n,e){var o;const i=yv(e==null?void 0:e.root),r=new Map,l=(u,f)=>{let d=u.children.length===(f==null?void 0:f.children.length)&&ME(u,f),g=d;for(let b=0;b{const o=e.get(l);if(o!=="same")if(o==="skip")for(const u of l.children)typeof u!="string"&&r(u);else i.push(l)};for(const l of n)typeof l=="string"?i.push(l):r(l);return i}function jo(n){return" ".repeat(n)}function Ja(n,e,i){const r=gv(e),l=[],o={},u=r.renderStringsAsRegex?hT:()=>!0,f=r.renderStringsAsRegex?fT:T=>T;let d=n.root.role==="fragment"?n.root.children:[n.root];const g=cT(n,i);i&&(d=uT(d,g));const b=(T,x)=>{if(e.depth&&x>e.depth)return;const _=lh(f(T));_&&l.push(jo(x)+"- text: "+_)},m=(T,x)=>{let _=T.role;if(T.name&&T.name.length<=900){const A=f(T.name);if(A){const N=A.startsWith("/")&&A.endsWith("/")?A:JSON.stringify(A);_+=" "+N}}return T.checked==="mixed"&&(_+=" [checked=mixed]"),T.checked===!0&&(_+=" [checked]"),T.disabled&&(_+=" [disabled]"),T.expanded&&(_+=" [expanded]"),T.active&&r.renderActive&&(_+=" [active]"),T.level&&(_+=` [level=${T.level}]`),T.pressed==="mixed"&&(_+=" [pressed=mixed]"),T.pressed===!0&&(_+=" [pressed]"),T.selected===!0&&(_+=" [selected]"),T.ref&&(_+=` [ref=${T.ref}]`,x&&lc(T)&&(_+=" [cursor=pointer]")),_},S=T=>(T==null?void 0:T.children.length)===1&&typeof T.children[0]=="string"&&!Object.keys(T.props).length?T.children[0]:void 0,w=(T,x,_)=>{if(e.depth&&x>e.depth)return;if(T.role==="iframe"&&T.ref&&(o[T.ref]=x),g.get(T)==="same"&&T.ref){l.push(jo(x)+`- ref=${T.ref} [unchanged]`);return}const A=!!i&&!x,N=jo(x)+"- "+(A?" ":"")+RE(m(T,_)),$=S(T),G=!!e.depth&&x===e.depth;if(!$&&(!T.children.length||G)&&!Object.keys(T.props).length)l.push(N);else if($!==void 0)u(T,$)?l.push(N+": "+lh(f($))):l.push(N);else{l.push(N+":");for(const[L,B]of Object.entries(T.props))l.push(jo(x+1)+"- /"+L+": "+lh(B));const U=!!T.ref&&_&&lc(T);for(const L of T.children)typeof L=="string"?b(u(T,L)?L:"",x+1):w(L,x+1,_&&!U)}};for(const T of d)typeof T=="string"?b(T,0):w(T,0,!!r.renderCursorPointer);return{text:l.join(` -`),iframeDepths:o}}function fT(n){const e=[{regex:/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/,replacement:"[0-9a-fA-F-]+"},{regex:/\b[\d,.]+[bkmBKM]+\b/,replacement:"[\\d,.]+[bkmBKM]+"},{regex:/\b\d+[hmsp]+\b/,replacement:"\\d+[hmsp]+"},{regex:/\b[\d,.]+[hmsp]+\b/,replacement:"[\\d,.]+[hmsp]+"},{regex:/\b\d+,\d+\b/,replacement:"\\d+,\\d+"},{regex:/\b\d+\.\d{2,}\b/,replacement:"\\d+\\.\\d+"},{regex:/\b\d{2,}\.\d+\b/,replacement:"\\d+\\.\\d+"},{regex:/\b\d{2,}\b/,replacement:"\\d+"}];let i="",r=0;const l=new RegExp(e.map(o=>"("+o.regex.source+")").join("|"),"g");return n.replace(l,(o,...u)=>{const f=u[u.length-2],d=u.slice(0,-2);i+=rc(n.slice(r,f));for(let g=0;ge.length)return!1;const i=e.length<=200&&n.name.length<=200?t_(e,n.name):"";let r=e;for(;i&&r.includes(i);)r=r.replace(i,"");return r.trim().length/e.length>.1}const bv=Symbol("element");function Ad(n){return n[bv]}function Lh(n,e){n[bv]=e}function dT(n,e){const i=LE(n,e);return i?Ad(i):void 0}const Ab=":host{font-size:13px;font-family:system-ui,Ubuntu,Droid Sans,sans-serif;color:#333}svg{position:absolute;height:0}x-pw-tooltip{-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);background-color:#fff;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:none;font-size:12.8px;font-weight:400;left:0;line-height:1.5;max-width:600px;position:absolute;top:0;padding:0;flex-direction:column;overflow:hidden}x-pw-tooltip-line{display:flex;max-width:600px;padding:6px;-webkit-user-select:none;user-select:none;cursor:pointer}x-pw-tooltip-footer{display:flex;max-width:600px;padding:6px;-webkit-user-select:none;user-select:none;color:#777}x-pw-dialog{background-color:#fff;pointer-events:auto;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:flex;flex-direction:column;position:absolute;z-index:10;font-size:13px}x-pw-dialog:not(.autosize){width:400px;height:150px}x-pw-dialog-body{display:flex;flex-direction:column;flex:auto}x-pw-dialog-body label{margin:5px 8px;display:flex;flex-direction:row;align-items:center}x-pw-highlight{position:absolute;top:0;left:0;width:0;height:0}x-pw-action-point{position:absolute;width:20px;height:20px;background:red;border-radius:10px;margin:-10px 0 0 -10px;z-index:2}x-pw-title{position:absolute;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);background-color:#00000080;color:#fff;border-radius:6px;padding:6px;font-size:24px;line-height:1.4;white-space:nowrap;-webkit-user-select:none;user-select:none;z-index:3}x-pw-user-overlays,x-pw-user-overlay{position:absolute;top:0;right:0;bottom:0;left:0}@keyframes pw-fade-out{0%{opacity:1}to{opacity:0}}x-pw-separator{height:1px;margin:6px 9px;background:#949494e5}x-pw-tool-gripper{height:28px;width:24px;margin:2px 0;cursor:grab}x-pw-tool-gripper:active{cursor:grabbing}x-pw-tool-gripper>x-div{width:16px;height:16px;margin:6px 4px;clip-path:url(#icon-gripper);background-color:#555}x-pw-tools-list>label{display:flex;align-items:center;margin:0 10px;-webkit-user-select:none;user-select:none}x-pw-tools-list{display:flex;width:100%;border-bottom:1px solid #dddddd}x-pw-tool-item{pointer-events:auto;height:28px;width:28px;border-radius:3px}x-pw-tool-item:not(.disabled){cursor:pointer}x-pw-tool-item:not(.disabled):hover{background-color:#dbdbdb}x-pw-tool-item.toggled{background-color:#8acae480}x-pw-tool-item.toggled:not(.disabled):hover{background-color:#8acae4c4}x-pw-tool-item>x-div{width:16px;height:16px;margin:6px;background-color:#3a3a3a}x-pw-tool-item.disabled>x-div{background-color:#61616180;cursor:default}x-pw-tool-item.record.toggled{background-color:transparent}x-pw-tool-item.record.toggled:not(.disabled):hover{background-color:#dbdbdb}x-pw-tool-item.record.toggled>x-div{background-color:#a1260d}x-pw-tool-item.record.disabled.toggled>x-div{opacity:.8}x-pw-tool-item.accept>x-div{background-color:#388a34}x-pw-tool-item.record>x-div{clip-path:url(#icon-circle-large-filled)}x-pw-tool-item.record.toggled>x-div{clip-path:url(#icon-stop-circle)}x-pw-tool-item.pick-locator>x-div{clip-path:url(#icon-inspect)}x-pw-tool-item.text>x-div{clip-path:url(#icon-whole-word)}x-pw-tool-item.visibility>x-div{clip-path:url(#icon-eye)}x-pw-tool-item.value>x-div{clip-path:url(#icon-symbol-constant)}x-pw-tool-item.snapshot>x-div{clip-path:url(#icon-gist)}x-pw-tool-item.accept>x-div{clip-path:url(#icon-check)}x-pw-tool-item.cancel>x-div{clip-path:url(#icon-close)}x-pw-tool-item.succeeded>x-div{clip-path:url(#icon-pass);background-color:#388a34!important}x-pw-overlay{position:absolute;top:0;max-width:min-content;z-index:2147483647;background:transparent;pointer-events:auto}x-pw-overlay x-pw-tools-list{background-color:#fffd;box-shadow:#0000001a 0 5px 5px;border-radius:3px;border-bottom:none}x-pw-overlay x-pw-tool-item{margin:2px}textarea.text-editor{font-family:system-ui,Ubuntu,Droid Sans,sans-serif;flex:auto;border:none;margin:6px 10px;color:#333;outline:1px solid transparent!important;resize:none;padding:0;font-size:13px}textarea.text-editor.does-not-match{outline:1px solid red!important}x-div{display:block}x-spacer{flex:auto}*{box-sizing:border-box}*[hidden]{display:none!important}x-locator-editor{flex:none;width:100%;height:60px;padding:4px;border-bottom:1px solid #dddddd;outline:1px solid transparent}x-locator-editor.does-not-match{outline:1px solid red}.CodeMirror{width:100%!important;height:100%!important}x-pw-action-list{flex:auto;display:flex;flex-direction:column;-webkit-user-select:none;user-select:none}x-pw-action-item{padding:6px 10px;cursor:pointer;overflow:hidden}x-pw-action-item:hover{background-color:#f2f2f2}x-pw-action-item:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}";class Lo{constructor(e){this._renderedEntries=[],this._userOverlays=new Map,this._userOverlayHidden=!1,this._language="javascript",this._injectedScript=e;const i=e.document;if(this._isUnderTest=e.isUnderTest,this._glassPaneElement=i.createElement("x-pw-glass"),this._glassPaneElement.setAttribute("popover","manual"),this._glassPaneElement.style.inset="0",this._glassPaneElement.style.width="100%",this._glassPaneElement.style.height="100%",this._glassPaneElement.style.maxWidth="none",this._glassPaneElement.style.maxHeight="none",this._glassPaneElement.style.padding="0",this._glassPaneElement.style.margin="0",this._glassPaneElement.style.border="none",this._glassPaneElement.style.overflow="visible",this._glassPaneElement.style.pointerEvents="none",this._glassPaneElement.style.display="flex",this._glassPaneElement.style.backgroundColor="transparent",this._actionPointElement=i.createElement("x-pw-action-point"),this._actionPointElement.setAttribute("hidden","true"),this._titleElement=i.createElement("x-pw-title"),this._titleElement.setAttribute("hidden","true"),this._userOverlayContainer=i.createElement("x-pw-user-overlays"),this._userOverlayContainer.setAttribute("hidden","true"),this._glassPaneShadow=this._glassPaneElement.attachShadow({mode:this._isUnderTest?"open":"closed"}),typeof this._glassPaneShadow.adoptedStyleSheets.push=="function"){const r=new this._injectedScript.window.CSSStyleSheet;r.replaceSync(Ab),this._glassPaneShadow.adoptedStyleSheets.push(r)}else{const r=this._injectedScript.document.createElement("style");r.textContent=Ab,this._glassPaneShadow.appendChild(r)}this._glassPaneShadow.appendChild(this._actionPointElement),this._glassPaneShadow.appendChild(this._titleElement),this._glassPaneShadow.appendChild(this._userOverlayContainer)}install(){this._injectedScript.document.documentElement&&((!this._injectedScript.document.documentElement.contains(this._glassPaneElement)||this._glassPaneElement.nextElementSibling)&&this._injectedScript.document.documentElement.appendChild(this._glassPaneElement),this._bringToFront())}_bringToFront(){this._glassPaneElement.hidePopover(),this._glassPaneElement.showPopover()}setLanguage(e){this._language=e}runHighlightOnRaf(e){this._rafRequest&&this._injectedScript.utils.builtins.cancelAnimationFrame(this._rafRequest);const i=this._injectedScript.querySelectorAll(e,this._injectedScript.document.documentElement),r=Ri(this._language,On(e)),l=i.length>1?"#f6b26b7f":"#6fa8dc7f";this.updateHighlight(i.map((o,u)=>{const f=i.length>1?` [${u+1} of ${i.length}]`:"";return{element:o,color:l,tooltipText:r+f}})),this._rafRequest=this._injectedScript.utils.builtins.requestAnimationFrame(()=>this.runHighlightOnRaf(e))}uninstall(){this._rafRequest&&this._injectedScript.utils.builtins.cancelAnimationFrame(this._rafRequest),this._glassPaneElement.remove()}showActionPoint(e,i,r){this._actionPointElement.style.top=i+"px",this._actionPointElement.style.left=e+"px",this._actionPointElement.hidden=!1,r?this._actionPointElement.style.animation=`pw-fade-out ${r}ms ease-out forwards`:this._actionPointElement.style.animation=""}hideActionPoint(){this._actionPointElement.hidden=!0}showActionTitle(e,i,r,l){if(this._titleElement.textContent=e,this._titleElement.hidden=!1,i){const o=i/4;this._titleElement.style.animation=`pw-fade-out ${o}ms ease-out ${i-o}ms forwards`}else this._titleElement.style.animation="";switch(this._titleElement.style.top="",this._titleElement.style.bottom="",this._titleElement.style.left="",this._titleElement.style.right="",this._titleElement.style.transform="",r){case"top-left":this._titleElement.style.top="6px",this._titleElement.style.left="6px";break;case"top":this._titleElement.style.top="6px",this._titleElement.style.left="50%",this._titleElement.style.transform="translateX(-50%)";break;case"bottom-left":this._titleElement.style.bottom="6px",this._titleElement.style.left="6px";break;case"bottom":this._titleElement.style.bottom="6px",this._titleElement.style.left="50%",this._titleElement.style.transform="translateX(-50%)";break;case"bottom-right":this._titleElement.style.bottom="6px",this._titleElement.style.right="6px";break;case"top-right":default:this._titleElement.style.top="6px",this._titleElement.style.right="6px";break}l&&(this._titleElement.style.fontSize=l+"px")}hideActionTitle(){this._titleElement.hidden=!0}addUserOverlay(e,i){const r=this._injectedScript.document.createElement("div");r.className="x-pw-user-overlay",r.innerHTML=i;for(const l of r.querySelectorAll("script"))l.remove();for(const l of r.querySelectorAll("*"))for(const o of[...l.attributes])o.name.startsWith("on")&&l.removeAttribute(o.name);return this._userOverlays.set(e,r),this._userOverlayContainer.appendChild(r),this._userOverlayContainer.hidden=this._userOverlayHidden,e}getUserOverlay(e){return this._userOverlays.get(e)}removeUserOverlay(e){const i=this._userOverlays.get(e);i&&(i.remove(),this._userOverlays.delete(e)),this._userOverlays.size===0&&(this._userOverlayContainer.hidden=!0)}setUserOverlaysVisible(e){this._userOverlayHidden=!e,this._userOverlayContainer.hidden=!e||this._userOverlays.size===0}clearHighlight(){var e,i;for(const r of this._renderedEntries)(e=r.highlightElement)==null||e.remove(),(i=r.tooltipElement)==null||i.remove();this._renderedEntries=[]}maskElements(e,i){this.updateHighlight(e.map(r=>({element:r,color:i})))}updateHighlight(e){if(!this._highlightIsUpToDate(e)){this.clearHighlight();for(const i of e){const r=this._createHighlightElement();this._glassPaneShadow.appendChild(r);let l;if(i.tooltipText){l=this._injectedScript.document.createElement("x-pw-tooltip"),this._glassPaneShadow.appendChild(l),l.style.top="0",l.style.left="0",l.style.display="flex";const o=this._injectedScript.document.createElement("x-pw-tooltip-line");o.textContent=i.tooltipText,l.appendChild(o)}this._renderedEntries.push({targetElement:i.element,box:Cb(i.box),color:i.color,borderColor:i.borderColor,fadeDuration:i.fadeDuration,cssStyle:i.cssStyle,tooltipElement:l,highlightElement:r})}for(const i of this._renderedEntries){if(!i.box&&!i.targetElement||(i.box=i.box||i.targetElement.getBoundingClientRect(),!i.tooltipElement))continue;const{anchorLeft:r,anchorTop:l}=this.tooltipPosition(i.box,i.tooltipElement);i.tooltipTop=l,i.tooltipLeft=r}for(const i of this._renderedEntries){i.tooltipElement&&(i.tooltipElement.style.top=i.tooltipTop+"px",i.tooltipElement.style.left=i.tooltipLeft+"px");const r=i.box;i.highlightElement.style.backgroundColor=i.color,i.highlightElement.style.left=r.x+"px",i.highlightElement.style.top=r.y+"px",i.highlightElement.style.width=r.width+"px",i.highlightElement.style.height=r.height+"px",i.highlightElement.style.display="block",i.borderColor&&(i.highlightElement.style.border="2px solid "+i.borderColor),i.fadeDuration&&(i.highlightElement.style.animation=`pw-fade-out ${i.fadeDuration}ms ease-out forwards`),i.cssStyle&&(i.highlightElement.style.cssText+=";"+i.cssStyle),this._isUnderTest&&console.error("Highlight box for test: "+JSON.stringify({x:r.x,y:r.y,width:r.width,height:r.height}))}}}firstBox(){var e;return(e=this._renderedEntries[0])==null?void 0:e.box}firstTooltipBox(){const e=this._renderedEntries[0];if(!(!e||!e.tooltipElement||e.tooltipLeft===void 0||e.tooltipTop===void 0))return{x:e.tooltipLeft,y:e.tooltipTop,left:e.tooltipLeft,top:e.tooltipTop,width:e.tooltipElement.offsetWidth,height:e.tooltipElement.offsetHeight,bottom:e.tooltipTop+e.tooltipElement.offsetHeight,right:e.tooltipLeft+e.tooltipElement.offsetWidth,toJSON:()=>{}}}tooltipPosition(e,i){const r=i.offsetWidth,l=i.offsetHeight,o=this._glassPaneElement.offsetWidth,u=this._glassPaneElement.offsetHeight;let f=Math.max(5,e.left);f+r>o-5&&(f=o-r-5);let d=Math.max(0,e.bottom)+5;return d+l>u-5&&(Math.max(0,e.top)>l+5?d=Math.max(0,e.top)-l-5:d=u-5-l),{anchorLeft:f,anchorTop:d}}_highlightIsUpToDate(e){if(e.length!==this._renderedEntries.length)return!1;for(let i=0;ii))return r+Math.max(e.bottom-n.bottom,0)+Math.max(n.top-e.top,0)}function gT(n,e,i){const r=e.left-n.right;if(!(r<0||i!==void 0&&r>i))return r+Math.max(e.bottom-n.bottom,0)+Math.max(n.top-e.top,0)}function mT(n,e,i){const r=e.top-n.bottom;if(!(r<0||i!==void 0&&r>i))return r+Math.max(n.left-e.left,0)+Math.max(e.right-n.right,0)}function yT(n,e,i){const r=n.top-e.bottom;if(!(r<0||i!==void 0&&r>i))return r+Math.max(n.left-e.left,0)+Math.max(e.right-n.right,0)}function bT(n,e,i){const r=i===void 0?50:i;let l=0;return n.left-e.right>=0&&(l+=n.left-e.right),e.left-n.right>=0&&(l+=e.left-n.right),e.top-n.bottom>=0&&(l+=e.top-n.bottom),n.top-e.bottom>=0&&(l+=n.top-e.bottom),l>r?void 0:l}const vT=["left-of","right-of","above","below","near"];function vv(n,e,i,r){const l=e.getBoundingClientRect(),o={"left-of":gT,"right-of":pT,above:mT,below:yT,near:bT}[n];let u;for(const f of i){if(f===e)continue;const d=o(l,f.getBoundingClientRect(),r);d!==void 0&&(u===void 0||d"?!!i:e.op==="="?r instanceof RegExp?typeof i=="string"&&!!i.match(r):i===r:typeof i!="string"||typeof r!="string"?!1:e.op==="*="?i.includes(r):e.op==="^="?i.startsWith(r):e.op==="$="?i.endsWith(r):e.op==="|="?i===r||i.startsWith(r+"-"):e.op==="~="?i.split(" ").includes(r):!1}function Cd(n){const e=n.ownerDocument;return n.nodeName==="SCRIPT"||n.nodeName==="NOSCRIPT"||n.nodeName==="STYLE"||e.head&&e.head.contains(n)}function Vt(n,e){let i=n.get(e);if(i===void 0){if(i={full:"",normalized:"",immediate:[]},!Cd(e)){let r="";if(e instanceof HTMLInputElement&&(e.type==="submit"||e.type==="button"))i={full:e.value,normalized:Ot(e.value),immediate:[e.value]};else{for(let l=e.firstChild;l;l=l.nextSibling)if(l.nodeType===Node.TEXT_NODE)i.full+=l.nodeValue||"",r+=l.nodeValue||"";else{if(l.nodeType===Node.COMMENT_NODE)continue;r&&i.immediate.push(r),r="",l.nodeType===Node.ELEMENT_NODE&&(i.full+=Vt(n,l).full)}r&&i.immediate.push(r),e.shadowRoot&&(i.full+=Vt(n,e.shadowRoot).full),i.full&&(i.normalized=Ot(i.full))}}n.set(e,i)}return i}function wc(n,e,i){if(Cd(e)||!i(Vt(n,e)))return"none";for(let r=e.firstChild;r;r=r.nextSibling)if(r.nodeType===Node.ELEMENT_NODE&&i(Vt(n,r)))return"selfAndChildren";return e.shadowRoot&&i(Vt(n,e.shadowRoot))?"selfAndChildren":"self"}function Sv(n,e){const i=rv(e);if(i)return i.map(o=>Vt(n,o));const r=e.getAttribute("aria-label");if(r!==null&&r.trim())return[{full:r,normalized:Ot(r),immediate:[r]}];const l=e.nodeName==="INPUT"&&e.type!=="hidden";if(["BUTTON","METER","OUTPUT","PROGRESS","SELECT","TEXTAREA"].includes(e.nodeName)||l){const o=e.labels;if(o)return[...o].map(u=>Vt(n,u))}return[]}const wv=["selected","checked","pressed","expanded","level","disabled","name","include-hidden"];wv.sort();function Ra(n,e,i){if(!e.includes(i))throw new Error(`"${n}" attribute is only supported for roles: ${e.slice().sort().map(r=>`"${r}"`).join(", ")}`)}function ar(n,e){if(n.op!==""&&!e.includes(n.value))throw new Error(`"${n.name}" must be one of ${e.map(i=>JSON.stringify(i)).join(", ")}`)}function lr(n,e){if(!e.includes(n.op))throw new Error(`"${n.name}" does not support "${n.op}" matcher`)}function wT(n,e){const i={role:e};for(const r of n)switch(r.name){case"checked":{Ra(r.name,hd,e),ar(r,[!0,!1,"mixed"]),lr(r,["","="]),i.checked=r.op===""?!0:r.value;break}case"pressed":{Ra(r.name,pd,e),ar(r,[!0,!1,"mixed"]),lr(r,["","="]),i.pressed=r.op===""?!0:r.value;break}case"selected":{Ra(r.name,fd,e),ar(r,[!0,!1]),lr(r,["","="]),i.selected=r.op===""?!0:r.value;break}case"expanded":{Ra(r.name,gd,e),ar(r,[!0,!1]),lr(r,["","="]),i.expanded=r.op===""?!0:r.value;break}case"level":{if(Ra(r.name,md,e),typeof r.value=="string"&&(r.value=+r.value),r.op!=="="||typeof r.value!="number"||Number.isNaN(r.value))throw new Error('"level" attribute must be compared to a number');i.level=r.value;break}case"disabled":{ar(r,[!0,!1]),lr(r,["","="]),i.disabled=r.op===""?!0:r.value;break}case"name":{if(r.op==="")throw new Error('"name" attribute must have a value');if(typeof r.value!="string"&&!(r.value instanceof RegExp))throw new Error('"name" attribute must be a string or a regular expression');i.name=r.value,i.nameOp=r.op,i.exact=r.caseSensitive;break}case"include-hidden":{ar(r,[!0,!1]),lr(r,["","="]),i.includeHidden=r.op===""?!0:r.value;break}default:throw new Error(`Unknown attribute "${r.name}", must be one of ${wv.map(l=>`"${l}"`).join(", ")}.`)}return i}function xT(n,e,i){const r=[],l=u=>{if(St(u)===e.role&&!(e.selected!==void 0&&av(u)!==e.selected)&&!(e.checked!==void 0&&lv(u)!==e.checked)&&!(e.pressed!==void 0&&ov(u)!==e.pressed)&&!(e.expanded!==void 0&&cv(u)!==e.expanded)&&!(e.level!==void 0&&uv(u)!==e.level)&&!(e.disabled!==void 0&&uc(u)!==e.disabled)&&!(!e.includeHidden&&dn(u))){if(e.name!==void 0){const f=Ot(il(u,!!e.includeHidden));if(typeof e.name=="string"&&(e.name=Ot(e.name)),i&&!e.exact&&e.nameOp==="="&&(e.nameOp="*="),!ST(f,{op:e.nameOp||"=",value:e.name,caseSensitive:!!e.exact}))return}r.push(u)}},o=u=>{const f=[];u.shadowRoot&&f.push(u.shadowRoot);for(const d of u.querySelectorAll("*"))l(d),d.shadowRoot&&f.push(d.shadowRoot);f.forEach(o)};return o(n),r}function Nb(n){return{queryAll:(e,i)=>{const r=Xa(i),l=r.name.toLowerCase();if(!l)throw new Error("Role must not be empty");const o=wT(r.attributes,l);vc();try{return xT(e,o,n)}finally{Sc()}}}}class _T{constructor(){this._retainCacheCounter=0,this._cacheText=new Map,this._cacheQueryCSS=new Map,this._cacheMatches=new Map,this._cacheQuery=new Map,this._cacheMatchesSimple=new Map,this._cacheMatchesParents=new Map,this._cacheCallMatches=new Map,this._cacheCallQuery=new Map,this._cacheQuerySimple=new Map,this._engines=new Map,this._engines.set("not",AT),this._engines.set("is",$a),this._engines.set("where",$a),this._engines.set("has",ET),this._engines.set("scope",TT),this._engines.set("light",CT),this._engines.set("visible",NT),this._engines.set("text",kT),this._engines.set("text-is",MT),this._engines.set("text-matches",OT),this._engines.set("has-text",jT),this._engines.set("right-of",Da("right-of")),this._engines.set("left-of",Da("left-of")),this._engines.set("above",Da("above")),this._engines.set("below",Da("below")),this._engines.set("near",Da("near")),this._engines.set("nth-match",LT);const e=[...this._engines.keys()];e.sort();const i=[...N0];if(i.sort(),e.join("|")!==i.join("|"))throw new Error(`Please keep customCSSNames in sync with evaluator engines: ${e.join("|")} vs ${i.join("|")}`)}begin(){++this._retainCacheCounter}end(){--this._retainCacheCounter,this._retainCacheCounter||(this._cacheQueryCSS.clear(),this._cacheMatches.clear(),this._cacheQuery.clear(),this._cacheMatchesSimple.clear(),this._cacheMatchesParents.clear(),this._cacheCallMatches.clear(),this._cacheCallQuery.clear(),this._cacheQuerySimple.clear(),this._cacheText.clear())}_cached(e,i,r,l){e.has(i)||e.set(i,[]);const o=e.get(i),u=o.find(d=>r.every((g,b)=>d.rest[b]===g));if(u)return u.result;const f=l();return o.push({rest:r,result:f}),f}_checkSelector(e){if(!(typeof e=="object"&&e&&(Array.isArray(e)||"simples"in e&&e.simples.length)))throw new Error(`Malformed selector "${e}"`);return e}matches(e,i,r){const l=this._checkSelector(i);this.begin();try{return this._cached(this._cacheMatches,e,[l,r.scope,r.pierceShadow,r.originalScope],()=>Array.isArray(l)?this._matchesEngine($a,e,l,r):(this._hasScopeClause(l)&&(r=this._expandContextForScopeMatching(r)),this._matchesSimple(e,l.simples[l.simples.length-1].selector,r)?this._matchesParents(e,l,l.simples.length-2,r):!1))}finally{this.end()}}query(e,i){const r=this._checkSelector(i);this.begin();try{return this._cached(this._cacheQuery,r,[e.scope,e.pierceShadow,e.originalScope],()=>{if(Array.isArray(r))return this._queryEngine($a,e,r);this._hasScopeClause(r)&&(e=this._expandContextForScopeMatching(e));const l=this._scoreMap;this._scoreMap=new Map;let o=this._querySimple(e,r.simples[r.simples.length-1].selector);return o=o.filter(u=>this._matchesParents(u,r,r.simples.length-2,e)),this._scoreMap.size&&o.sort((u,f)=>{const d=this._scoreMap.get(u),g=this._scoreMap.get(f);return d===g?0:d===void 0?1:g===void 0?-1:d-g}),this._scoreMap=l,o})}finally{this.end()}}_markScore(e,i){this._scoreMap&&this._scoreMap.set(e,i)}_hasScopeClause(e){return e.simples.some(i=>i.selector.functions.some(r=>r.name==="scope"))}_expandContextForScopeMatching(e){if(e.scope.nodeType!==1)return e;const i=xt(e.scope);return i?{...e,scope:i,originalScope:e.originalScope||e.scope}:e}_matchesSimple(e,i,r){return this._cached(this._cacheMatchesSimple,e,[i,r.scope,r.pierceShadow,r.originalScope],()=>{if(e===r.scope||i.css&&!this._matchesCSS(e,i.css))return!1;for(const l of i.functions)if(!this._matchesEngine(this._getEngine(l.name),e,l.args,r))return!1;return!0})}_querySimple(e,i){return i.functions.length?this._cached(this._cacheQuerySimple,i,[e.scope,e.pierceShadow,e.originalScope],()=>{let r=i.css;const l=i.functions;r==="*"&&l.length&&(r=void 0);let o,u=-1;r!==void 0?o=this._queryCSS(e,r):(u=l.findIndex(f=>this._getEngine(f.name).query!==void 0),u===-1&&(u=0),o=this._queryEngine(this._getEngine(l[u].name),e,l[u].args));for(let f=0;fthis._matchesEngine(d,g,l[f].args,e)))}for(let f=0;fthis._matchesEngine(d,g,l[f].args,e)))}return o}):this._queryCSS(e,i.css||"*")}_matchesParents(e,i,r,l){return r<0?!0:this._cached(this._cacheMatchesParents,e,[i,r,l.scope,l.pierceShadow,l.originalScope],()=>{const{selector:o,combinator:u}=i.simples[r];if(u===">"){const f=Ro(e,l);return!f||!this._matchesSimple(f,o,l)?!1:this._matchesParents(f,i,r-1,l)}if(u==="+"){const f=uh(e,l);return!f||!this._matchesSimple(f,o,l)?!1:this._matchesParents(f,i,r-1,l)}if(u===""){let f=Ro(e,l);for(;f;){if(this._matchesSimple(f,o,l)){if(this._matchesParents(f,i,r-1,l))return!0;if(i.simples[r-1].combinator==="")break}f=Ro(f,l)}return!1}if(u==="~"){let f=uh(e,l);for(;f;){if(this._matchesSimple(f,o,l)){if(this._matchesParents(f,i,r-1,l))return!0;if(i.simples[r-1].combinator==="~")break}f=uh(f,l)}return!1}if(u===">="){let f=e;for(;f;){if(this._matchesSimple(f,o,l)){if(this._matchesParents(f,i,r-1,l))return!0;if(i.simples[r-1].combinator==="")break}f=Ro(f,l)}return!1}throw new Error(`Unsupported combinator "${u}"`)})}_matchesEngine(e,i,r,l){if(e.matches)return this._callMatches(e,i,r,l);if(e.query)return this._callQuery(e,r,l).includes(i);throw new Error('Selector engine should implement "matches" or "query"')}_queryEngine(e,i,r){if(e.query)return this._callQuery(e,r,i);if(e.matches)return this._queryCSS(i,"*").filter(l=>this._callMatches(e,l,r,i));throw new Error('Selector engine should implement "matches" or "query"')}_callMatches(e,i,r,l){return this._cached(this._cacheCallMatches,i,[e,l.scope,l.pierceShadow,l.originalScope,...r],()=>e.matches(i,r,l,this))}_callQuery(e,i,r){return this._cached(this._cacheCallQuery,e,[r.scope,r.pierceShadow,r.originalScope,...i],()=>e.query(r,i,this))}_matchesCSS(e,i){return e.matches(i)}_queryCSS(e,i){return this._cached(this._cacheQueryCSS,i,[e.scope,e.pierceShadow,e.originalScope],()=>{let r=[];function l(o){if(r=r.concat([...o.querySelectorAll(i)]),!!e.pierceShadow){o.shadowRoot&&l(o.shadowRoot);for(const u of o.querySelectorAll("*"))u.shadowRoot&&l(u.shadowRoot)}}return l(e.scope),r})}_getEngine(e){const i=this._engines.get(e);if(!i)throw new Error(`Unknown selector engine "${e}"`);return i}}const $a={matches(n,e,i,r){if(e.length===0)throw new Error('"is" engine expects non-empty selector list');return e.some(l=>r.matches(n,l,i))},query(n,e,i){if(e.length===0)throw new Error('"is" engine expects non-empty selector list');let r=[];for(const l of e)r=r.concat(i.query(n,l));return e.length===1?r:xv(r)}},ET={matches(n,e,i,r){if(e.length===0)throw new Error('"has" engine expects non-empty selector list');return r.query({...i,scope:n},e).length>0}},TT={matches(n,e,i,r){if(e.length!==0)throw new Error('"scope" engine expects no arguments');const l=i.originalScope||i.scope;return l.nodeType===9?n===l.documentElement:n===l},query(n,e,i){if(e.length!==0)throw new Error('"scope" engine expects no arguments');const r=n.originalScope||n.scope;if(r.nodeType===9){const l=r.documentElement;return l?[l]:[]}return r.nodeType===1?[r]:[]}},AT={matches(n,e,i,r){if(e.length===0)throw new Error('"not" engine expects non-empty selector list');return!r.matches(n,e,i)}},CT={query(n,e,i){return i.query({...n,pierceShadow:!1},e)},matches(n,e,i,r){return r.matches(n,e,{...i,pierceShadow:!1})}},NT={matches(n,e,i,r){if(e.length)throw new Error('"visible" engine expects no arguments');return Di(n)}},kT={matches(n,e,i,r){if(e.length!==1||typeof e[0]!="string")throw new Error('"text" engine expects a single string');const l=Ot(e[0]).toLowerCase(),o=u=>u.normalized.toLowerCase().includes(l);return wc(r._cacheText,n,o)==="self"}},MT={matches(n,e,i,r){if(e.length!==1||typeof e[0]!="string")throw new Error('"text-is" engine expects a single string');const l=Ot(e[0]),o=u=>!l&&!u.immediate.length?!0:u.immediate.some(f=>Ot(f)===l);return wc(r._cacheText,n,o)!=="none"}},OT={matches(n,e,i,r){if(e.length===0||typeof e[0]!="string"||e.length>2||e.length===2&&typeof e[1]!="string")throw new Error('"text-matches" engine expects a regexp body and optional regexp flags');const l=new RegExp(e[0],e.length===2?e[1]:void 0),o=u=>l.test(u.full);return wc(r._cacheText,n,o)==="self"}},jT={matches(n,e,i,r){if(e.length!==1||typeof e[0]!="string")throw new Error('"has-text" engine expects a single string');if(Cd(n))return!1;const l=Ot(e[0]).toLowerCase();return(u=>u.normalized.toLowerCase().includes(l))(Vt(r._cacheText,n))}};function Da(n){return{matches(e,i,r,l){const o=i.length&&typeof i[i.length-1]=="number"?i[i.length-1]:void 0,u=o===void 0?i:i.slice(0,i.length-1);if(i.length<1+(o===void 0?0:1))throw new Error(`"${n}" engine expects a selector list and optional maximum distance in pixels`);const f=l.query(r,u),d=vv(n,e,f,o);return d===void 0?!1:(l._markScore(e,d),!0)}}}const LT={query(n,e,i){let r=e[e.length-1];if(e.length<2)throw new Error('"nth-match" engine expects non-empty selector list and an index argument');if(typeof r!="number"||r<1)throw new Error('"nth-match" engine expects a one-based index as the last argument');const l=$a.query(n,e.slice(0,e.length-1),i);return r--,r1){const d=new Set(f.children);f.children=[];let g=u.firstElementChild;for(;g&&f.children.lengthPo(b)))]}else{const f=os(r,n,e,i)||Ia(n,e,i);l=[Po(f)]}}const o=l[0],u=n.parseSelector(o);return{selector:o,selectors:l,elements:n.querySelectorAll(u,i.root??e.ownerDocument)}}finally{cd(),Sc(),n._evaluator.end()}}function os(n,e,i,r){if(r.root&&!jh(r.root,i))throw new Error("Target element must belong to the root's subtree");if(i===r.root)return[{engine:"css",selector:":scope",score:1}];if(i.ownerDocument.documentElement===i)return[{engine:"css",selector:"html",score:1}];let l=null;const o=f=>{(!l||cs(f)cs(f.candidate)-cs(d.candidate));for(const{candidate:f,isTextCandidate:d}of u){const g=e.querySelectorAll(e.parseSelector(Po(f)),r.root??i.ownerDocument);if(!g.includes(i))continue;if(g.length===1){o(f);break}const b=g.indexOf(i);if(!(b>5)&&(o([...f,{engine:"nth",selector:String(b),score:Rh}]),!r.isRecursive))for(let m=xt(i);m&&m!==r.root;m=xt(m)){const S=g.filter($=>jh(m,$)&&$!==m),w=S.indexOf(i);if(S.length>5||w===-1||w===b&&S.length>1)continue;const T=S.length===1?f:[...f,{engine:"nth",selector:String(w),score:Rh}];if(l&&cs([{engine:"",selector:"",score:1},...T])>=cs(l))continue;const _=!!r.noText||d,A=_?n.disallowText:n.allowText;let N=A.get(m);N===void 0&&(N=os(n,e,m,{...r,isRecursive:!0,noText:_})||Ia(e,m,r),A.set(m,N)),N&&o([...N,...T])}}return l}function YT(n,e,i){const r=[];{for(const u of["data-testid","data-test-id","data-test"])u!==i.testIdAttributeName&&e.getAttribute(u)&&r.push({engine:"css",selector:`[${u}=${hr(e.getAttribute(u))}]`,score:RT});if(!i.noCSSId){const u=e.getAttribute("id");u&&!QT(u)&&r.push({engine:"css",selector:Ov(u),score:GT})}r.push({engine:"css",selector:ti(e),score:Mv})}if(e.nodeName==="IFRAME"){for(const u of["name","title"])e.getAttribute(u)&&r.push({engine:"css",selector:`${ti(e)}[${u}=${hr(e.getAttribute(u))}]`,score:DT});return e.getAttribute(i.testIdAttributeName)&&r.push({engine:"css",selector:`[${i.testIdAttributeName}=${hr(e.getAttribute(i.testIdAttributeName))}]`,score:kb}),Dh([r]),r}if(e.getAttribute(i.testIdAttributeName)&&r.push({engine:"internal:testid",selector:`[${i.testIdAttributeName}=${Mt(e.getAttribute(i.testIdAttributeName),!0)}]`,score:kb}),e.nodeName==="INPUT"||e.nodeName==="TEXTAREA"){const u=e;if(u.placeholder){r.push({engine:"internal:attr",selector:`[placeholder=${Mt(u.placeholder,!0)}]`,score:UT});for(const f of mr(u.placeholder))r.push({engine:"internal:attr",selector:`[placeholder=${Mt(f.text,!1)}]`,score:Tv-f.scoreBonus})}}const l=Sv(n._evaluator._cacheText,e);for(const u of l){const f=u.normalized;r.push({engine:"internal:label",selector:$t(f,!0),score:HT});for(const d of mr(f))r.push({engine:"internal:label",selector:$t(d.text,!1),score:Av-d.scoreBonus})}const o=St(e);return o&&!["none","presentation"].includes(o)&&r.push({engine:"internal:role",selector:o,score:kv}),e.getAttribute("name")&&["BUTTON","FORM","FIELDSET","FRAME","IFRAME","INPUT","KEYGEN","OBJECT","OUTPUT","SELECT","TEXTAREA","MAP","META","PARAM"].includes(e.nodeName)&&r.push({engine:"css",selector:`${ti(e)}[name=${hr(e.getAttribute("name"))}]`,score:fh}),["INPUT","TEXTAREA"].includes(e.nodeName)&&e.getAttribute("type")!=="hidden"&&e.getAttribute("type")&&r.push({engine:"css",selector:`${ti(e)}[type=${hr(e.getAttribute("type"))}]`,score:fh}),["INPUT","TEXTAREA","SELECT"].includes(e.nodeName)&&e.getAttribute("type")!=="hidden"&&r.push({engine:"css",selector:ti(e),score:fh+1}),Dh([r]),r}function FT(n,e,i){if(e.nodeName==="SELECT")return[];const r=[],l=e.getAttribute("title");if(l){r.push([{engine:"internal:attr",selector:`[title=${Mt(l,!0)}]`,score:IT}]);for(const g of mr(l))r.push([{engine:"internal:attr",selector:`[title=${Mt(g.text,!1)}]`,score:Nv-g.scoreBonus}])}const o=e.getAttribute("alt");if(o&&["APPLET","AREA","IMG","INPUT"].includes(e.nodeName)){r.push([{engine:"internal:attr",selector:`[alt=${Mt(o,!0)}]`,score:qT}]);for(const g of mr(o))r.push([{engine:"internal:attr",selector:`[alt=${Mt(g.text,!1)}]`,score:Cv-g.scoreBonus}])}const u=Vt(n._evaluator._cacheText,e).normalized,f=u?mr(u):[];if(u){if(i){u.length<=80&&r.push([{engine:"internal:text",selector:$t(u,!0),score:$T}]);for(const b of f)r.push([{engine:"internal:text",selector:$t(b.text,!1),score:Qo-b.scoreBonus}])}const g={engine:"css",selector:ti(e),score:Mv};for(const b of f)r.push([g,{engine:"internal:has-text",selector:$t(b.text,!1),score:Qo-b.scoreBonus}]);if(i&&u.length<=80){const b=new RegExp("^"+rc(u)+"$");r.push([g,{engine:"internal:has-text",selector:$t(b,!1),score:Mb}])}}const d=St(e);if(d&&!["none","presentation"].includes(d)){const g=il(e,!1);if(g&&!g.match(new RegExp("^\\p{Co}+$","u"))){const b={engine:"internal:role",selector:`${d}[name=${Mt(g,!0)}]`,score:BT};r.push([b]);for(const m of mr(g))r.push([{engine:"internal:role",selector:`${d}[name=${Mt(m.text,!1)}]`,score:Ev-m.scoreBonus}])}else{const b={engine:"internal:role",selector:`${d}`,score:kv};for(const m of f)r.push([b,{engine:"internal:has-text",selector:$t(m.text,!1),score:Qo-m.scoreBonus}]);if(i&&u.length<=80){const m=new RegExp("^"+rc(u)+"$");r.push([b,{engine:"internal:has-text",selector:$t(m,!1),score:Mb}])}}}return Dh(r),r}function Ov(n){return/^[a-zA-Z][a-zA-Z0-9\-\_]+$/.test(n)?"#"+n:`[id=${hr(n)}]`}function hh(n){return n.some(e=>e.engine==="css"&&(e.selector.startsWith("#")||e.selector.startsWith('[id="')))}function Ia(n,e,i){const r=i.root??e.ownerDocument,l=[];function o(f){const d=l.slice();f&&d.unshift(f);const g=d.join(" > "),b=n.parseSelector(g);return n.querySelector(b,r,!1)===e?g:void 0}function u(f){const d={engine:"css",selector:f,score:KT},g=n.parseSelector(f),b=n.querySelectorAll(g,r);if(b.length===1)return[d];const m={engine:"nth",selector:String(b.indexOf(e)),score:Rh};return[d,m]}for(let f=e;f&&f!==r;f=xt(f)){let d="";if(f.id&&!i.noCSSId){const m=Ov(f.id),S=o(m);if(S)return u(S);d=m}const g=f.parentNode,b=[...f.classList].map(PT);for(let m=0;m_.nodeName===S).indexOf(f)===0?ti(f):`${ti(f)}:nth-child(${1+m.indexOf(f)})`,x=o(T);if(x)return u(x);d||(d=T)}else d||(d=ti(f));l.unshift(d)}return u(o())}function Dh(n){for(const e of n)for(const i of e)i.score>zT&&i.score>"),i=r,r==="css"?e.push(l):e.push(`${r}=${l}`);return e.join(" ")}function cs(n){let e=0;for(let i=0;i="a"&&l<="z"?o="lower":l>="A"&&l<="Z"?o="upper":l>="0"&&l<="9"?o="digit":o="other",o==="lower"&&e==="upper"){e=o;continue}e&&e!==o&&++i,e=o}}return i>=n.length/4}function Do(n,e){if(n.length<=e)return n;n=n.substring(0,e);const i=n.match(/^(.*)\b(.+?)$/);return i?i[1].trimEnd():""}function mr(n){let e=[];{const i=n.match(/^([\d.,]+)[^.,\w]/),r=i?i[1].length:0;if(r){const l=Do(n.substring(r).trimStart(),80);e.push({text:l,scoreBonus:l.length<=30?2:1})}}{const i=n.match(/[^.,\w]([\d.,]+)$/),r=i?i[1].length:0;if(r){const l=Do(n.substring(0,n.length-r).trimEnd(),80);e.push({text:l,scoreBonus:l.length<=30?2:1})}}return n.length<=30?e.push({text:n,scoreBonus:0}):(e.push({text:Do(n,80),scoreBonus:0}),e.push({text:Do(n,30),scoreBonus:1})),e=e.filter(i=>i.text),e.length||e.push({text:n.substring(0,80),scoreBonus:0}),e}function ti(n){return n.nodeName.toLocaleLowerCase().replace(/[:\.]/g,e=>"\\"+e)}function PT(n){let e="";for(let i=0;i=1&&i<=31||i>=48&&i<=57&&(e===0||e===1&&n.charCodeAt(0)===45)?"\\"+i.toString(16)+" ":e===0&&i===45&&n.length===1?"\\"+n.charAt(e):i>=128||i===45||i===95||i>=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122?n.charAt(e):"\\"+n.charAt(e)}const jb={queryAll(n,e){e.startsWith("/")&&n.nodeType!==Node.DOCUMENT_NODE&&(e="."+e);const i=[],r=n.ownerDocument||n;if(!r)return i;const l=r.evaluate(e,n,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE);for(let o=l.iterateNext();o;o=l.iterateNext())o.nodeType===Node.ELEMENT_NODE&&i.push(o);return i}};function Nd(n,e,i){return`internal:attr=[${n}=${Mt(e,(i==null?void 0:i.exact)||!1)}]`}function ZT(n,e){return`internal:testid=[${n}=${Mt(e,!0)}]`}function WT(n,e){return"internal:label="+$t(n,!!(e!=null&&e.exact))}function eA(n,e){return Nd("alt",n,e)}function tA(n,e){return Nd("title",n,e)}function nA(n,e){return Nd("placeholder",n,e)}function iA(n,e){return"internal:text="+$t(n,!!(e!=null&&e.exact))}function sA(n,e={}){const i=[];return e.checked!==void 0&&i.push(["checked",String(e.checked)]),e.disabled!==void 0&&i.push(["disabled",String(e.disabled)]),e.selected!==void 0&&i.push(["selected",String(e.selected)]),e.expanded!==void 0&&i.push(["expanded",String(e.expanded)]),e.includeHidden!==void 0&&i.push(["include-hidden",String(e.includeHidden)]),e.level!==void 0&&i.push(["level",String(e.level)]),e.name!==void 0&&i.push(["name",Mt(e.name,!!e.exact)]),e.pressed!==void 0&&i.push(["pressed",String(e.pressed)]),`internal:role=${n}${i.map(([r,l])=>`[${r}=${l}]`).join("")}`}const za=Symbol("selector"),rA=class Va{constructor(e,i,r){if(r!=null&&r.hasText&&(i+=` >> internal:has-text=${$t(r.hasText,!1)}`),r!=null&&r.hasNotText&&(i+=` >> internal:has-not-text=${$t(r.hasNotText,!1)}`),r!=null&&r.has&&(i+=" >> internal:has="+JSON.stringify(r.has[za])),r!=null&&r.hasNot&&(i+=" >> internal:has-not="+JSON.stringify(r.hasNot[za])),(r==null?void 0:r.visible)!==void 0&&(i+=` >> visible=${r.visible?"true":"false"}`),this[za]=i,i){const u=e.parseSelector(i);this.element=e.querySelector(u,e.document,!1),this.elements=e.querySelectorAll(u,e.document)}const l=i,o=this;o.locator=(u,f)=>new Va(e,l?l+" >> "+u:u,f),o.getByTestId=u=>o.locator(ZT(e.testIdAttributeNameForStrictErrorAndConsoleCodegen(),u)),o.getByAltText=(u,f)=>o.locator(eA(u,f)),o.getByLabel=(u,f)=>o.locator(WT(u,f)),o.getByPlaceholder=(u,f)=>o.locator(nA(u,f)),o.getByText=(u,f)=>o.locator(iA(u,f)),o.getByTitle=(u,f)=>o.locator(tA(u,f)),o.getByRole=(u,f={})=>o.locator(sA(u,f)),o.filter=u=>new Va(e,i,u),o.first=()=>o.locator("nth=0"),o.last=()=>o.locator("nth=-1"),o.nth=u=>o.locator(`nth=${u}`),o.and=u=>new Va(e,l+" >> internal:and="+JSON.stringify(u[za])),o.or=u=>new Va(e,l+" >> internal:or="+JSON.stringify(u[za]))}};let aA=rA;class lA{constructor(e){this._injectedScript=e}install(){this._injectedScript.window.playwright||(this._injectedScript.window.playwright={$:(e,i)=>this._querySelector(e,!!i),$$:e=>this._querySelectorAll(e),inspect:e=>this._inspect(e),selector:e=>this._selector(e),generateLocator:(e,i)=>this._generateLocator(e,i),ariaSnapshot:(e,i)=>this._injectedScript.ariaSnapshot(e||this._injectedScript.document.body,i||{mode:"default"}),resume:()=>this._resume(),...new aA(this._injectedScript,"")},delete this._injectedScript.window.playwright.filter,delete this._injectedScript.window.playwright.first,delete this._injectedScript.window.playwright.last,delete this._injectedScript.window.playwright.nth,delete this._injectedScript.window.playwright.and,delete this._injectedScript.window.playwright.or)}_querySelector(e,i){if(typeof e!="string")throw new Error("Usage: playwright.query('Playwright >> selector').");const r=this._injectedScript.parseSelector(e);return this._injectedScript.querySelector(r,this._injectedScript.document,i)}_querySelectorAll(e){if(typeof e!="string")throw new Error("Usage: playwright.$$('Playwright >> selector').");const i=this._injectedScript.parseSelector(e);return this._injectedScript.querySelectorAll(i,this._injectedScript.document)}_inspect(e){if(typeof e!="string")throw new Error("Usage: playwright.inspect('Playwright >> selector').");this._injectedScript.window.inspect(this._querySelector(e,!1))}_selector(e){if(!(e instanceof Element))throw new Error("Usage: playwright.selector(element).");return this._injectedScript.generateSelectorSimple(e)}_generateLocator(e,i){if(!(e instanceof Element))throw new Error("Usage: playwright.locator(element).");const r=this._injectedScript.generateSelectorSimple(e);return Ri(i||"javascript",r)}_resume(){if(!this._injectedScript.window.__pw_resume)return!1;this._injectedScript.window.__pw_resume().catch(()=>{})}}function oA(n){try{return n instanceof RegExp||Object.prototype.toString.call(n)==="[object RegExp]"}catch{return!1}}function cA(n){try{return n instanceof Date||Object.prototype.toString.call(n)==="[object Date]"}catch{return!1}}function uA(n){try{return n instanceof URL||Object.prototype.toString.call(n)==="[object URL]"}catch{return!1}}function fA(n){var e;try{return n instanceof Error||n&&((e=Object.getPrototypeOf(n))==null?void 0:e.name)==="Error"}catch{return!1}}function hA(n,e){try{return n instanceof e||Object.prototype.toString.call(n)===`[object ${e.name}]`}catch{return!1}}function dA(n){try{return n instanceof ArrayBuffer||Object.prototype.toString.call(n)==="[object ArrayBuffer]"}catch{return!1}}const jv={i8:Int8Array,ui8:Uint8Array,ui8c:Uint8ClampedArray,i16:Int16Array,ui16:Uint16Array,i32:Int32Array,ui32:Uint32Array,f32:Float32Array,f64:Float64Array,bi64:BigInt64Array,bui64:BigUint64Array};function Lb(n){if("toBase64"in n)return n.toBase64();const e=Array.from(new Uint8Array(n.buffer,n.byteOffset,n.byteLength)).map(i=>String.fromCharCode(i)).join("");return btoa(e)}function Rb(n,e){const i=atob(n),r=new Uint8Array(i.length);for(let l=0;l";if(typeof globalThis.Document=="function"&&n instanceof globalThis.Document)return"ref: ";if(typeof globalThis.Node=="function"&&n instanceof globalThis.Node)return"ref: "}return Lv(n,e,i)}function Lv(n,e,i){var o;const r=e(n);if("fallThrough"in r)n=r.fallThrough;else return r;if(typeof n=="symbol")return{v:"undefined"};if(Object.is(n,void 0))return{v:"undefined"};if(Object.is(n,null))return{v:"null"};if(Object.is(n,NaN))return{v:"NaN"};if(Object.is(n,1/0))return{v:"Infinity"};if(Object.is(n,-1/0))return{v:"-Infinity"};if(Object.is(n,-0))return{v:"-0"};if(typeof n=="boolean"||typeof n=="number"||typeof n=="string")return n;if(typeof n=="bigint")return{bi:n.toString()};if(fA(n)){let u;return(o=n.stack)!=null&&o.startsWith(n.name+": "+n.message)?u=n.stack:u=`${n.name}: ${n.message} -${n.stack}`,{e:{n:n.name,m:n.message,s:u}}}if(cA(n))return{d:n.toJSON()};if(uA(n))return{u:n.toJSON()};if(oA(n))return{r:{p:n.source,f:n.flags}};for(const[u,f]of Object.entries(jv))if(hA(n,f))return{ta:{b:Lb(n),k:u}};if(dA(n))return{ab:{b:Lb(new Uint8Array(n))}};const l=i.visited.get(n);if(l)return{ref:l};if(Array.isArray(n)){const u=[],f=++i.lastId;i.visited.set(n,f);for(let d=0;d({fallThrough:r}))}_promiseAwareJsonValueNoThrow(e){const i=r=>{try{return this.jsonValue(!0,r)}catch{return}};return e&&typeof e=="object"&&typeof e.then=="function"?(async()=>{const r=await e;return i(r)})():i(e)}}class Rv{constructor(e,i){this._testIdAttributeNameForStrictErrorAndConsoleCodegen="data-testid",this._lastAriaSnapshotForTrack=new Map,this.utils={asLocator:Ri,cacheNormalizedWhitespaces:Wx,elementText:Vt,getAriaRole:St,getElementAccessibleDescription:wb,getElementAccessibleName:il,isElementVisible:Di,isInsideScope:jh,normalizeWhiteSpace:Ot,parseAriaSnapshot:sd,generateAriaTree:Pa,findNewElement:dT,builtins:null},this.window=e,this.document=e.document,this.isUnderTest=i.isUnderTest,this.utils.builtins=new gA(e,i.isUnderTest).builtins,this._sdkLanguage=i.sdkLanguage,this._testIdAttributeNameForStrictErrorAndConsoleCodegen=i.testIdAttributeName,this._evaluator=new _T,this.consoleApi=new lA(this),this.onGlobalListenersRemoved=new Set,this._autoClosingTags=new Set(["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","MENUITEM","META","PARAM","SOURCE","TRACK","WBR"]),this._booleanAttributes=new Set(["checked","selected","disabled","readonly","multiple"]),this._eventTypes=new Map([["auxclick","mouse"],["click","mouse"],["dblclick","mouse"],["mousedown","mouse"],["mouseeenter","mouse"],["mouseleave","mouse"],["mousemove","mouse"],["mouseout","mouse"],["mouseover","mouse"],["mouseup","mouse"],["mouseleave","mouse"],["mousewheel","mouse"],["keydown","keyboard"],["keyup","keyboard"],["keypress","keyboard"],["textInput","keyboard"],["touchstart","touch"],["touchmove","touch"],["touchend","touch"],["touchcancel","touch"],["pointerover","pointer"],["pointerout","pointer"],["pointerenter","pointer"],["pointerleave","pointer"],["pointerdown","pointer"],["pointerup","pointer"],["pointermove","pointer"],["pointercancel","pointer"],["gotpointercapture","pointer"],["lostpointercapture","pointer"],["focus","focus"],["blur","focus"],["drag","drag"],["dragstart","drag"],["dragend","drag"],["dragover","drag"],["dragenter","drag"],["dragleave","drag"],["dragexit","drag"],["drop","drag"],["wheel","wheel"],["deviceorientation","deviceorientation"],["deviceorientationabsolute","deviceorientation"],["devicemotion","devicemotion"]]),this._hoverHitTargetInterceptorEvents=new Set(["mousemove"]),this._tapHitTargetInterceptorEvents=new Set(["pointerdown","pointerup","touchstart","touchend","touchcancel"]),this._mouseHitTargetInterceptorEvents=new Set(["mousedown","mouseup","pointerdown","pointerup","click","auxclick","dblclick","contextmenu"]),this._allHitTargetInterceptorEvents=new Set([...this._hoverHitTargetInterceptorEvents,...this._tapHitTargetInterceptorEvents,...this._mouseHitTargetInterceptorEvents]),this._engines=new Map,this._engines.set("xpath",jb),this._engines.set("xpath:light",jb),this._engines.set("role",Nb(!1)),this._engines.set("text",this._createTextEngine(!0,!1)),this._engines.set("text:light",this._createTextEngine(!1,!1)),this._engines.set("id",this._createAttributeEngine("id",!0)),this._engines.set("id:light",this._createAttributeEngine("id",!1)),this._engines.set("data-testid",this._createAttributeEngine("data-testid",!0)),this._engines.set("data-testid:light",this._createAttributeEngine("data-testid",!1)),this._engines.set("data-test-id",this._createAttributeEngine("data-test-id",!0)),this._engines.set("data-test-id:light",this._createAttributeEngine("data-test-id",!1)),this._engines.set("data-test",this._createAttributeEngine("data-test",!0)),this._engines.set("data-test:light",this._createAttributeEngine("data-test",!1)),this._engines.set("css",this._createCSSEngine()),this._engines.set("nth",{queryAll:()=>[]}),this._engines.set("visible",this._createVisibleEngine()),this._engines.set("internal:control",this._createControlEngine()),this._engines.set("internal:has",this._createHasEngine()),this._engines.set("internal:has-not",this._createHasNotEngine()),this._engines.set("internal:and",{queryAll:()=>[]}),this._engines.set("internal:or",{queryAll:()=>[]}),this._engines.set("internal:chain",this._createInternalChainEngine()),this._engines.set("internal:label",this._createInternalLabelEngine()),this._engines.set("internal:text",this._createTextEngine(!0,!0)),this._engines.set("internal:has-text",this._createInternalHasTextEngine()),this._engines.set("internal:has-not-text",this._createInternalHasNotTextEngine()),this._engines.set("internal:attr",this._createNamedAttributeEngine()),this._engines.set("internal:testid",this._createNamedAttributeEngine()),this._engines.set("internal:role",Nb(!0)),this._engines.set("internal:describe",this._createDescribeEngine()),this._engines.set("aria-ref",this._createAriaRefEngine());for(const{name:r,source:l}of i.customEngines)this._engines.set(r,this.eval(l));this._stableRafCount=i.stableRafCount,this._browserName=i.browserName,this._isUtilityWorld=!!i.isUtilityWorld,DE({browserNameForWorkarounds:i.browserName}),this._setupGlobalListenersRemovalDetection(),this._setupHitTargetInterceptors(),this.isUnderTest&&(this.window.__injectedScript=this)}eval(e){return this.window.eval(e)}testIdAttributeNameForStrictErrorAndConsoleCodegen(){return this._testIdAttributeNameForStrictErrorAndConsoleCodegen}parseSelector(e){const i=ol(e);return Jx(i,r=>{if(!this._engines.has(r.name))throw this.createStacklessError(`Unknown engine "${r.name}" while parsing selector ${e}`)}),i}generateSelector(e,i){return Ob(this,e,i)}generateSelectorSimple(e,i){return Ob(this,e,{...i,testIdAttributeName:this._testIdAttributeNameForStrictErrorAndConsoleCodegen}).selector}querySelector(e,i,r){const l=this.querySelectorAll(e,i);if(r&&l.length>1)throw this.strictModeViolationError(e,l);return this.checkDeprecatedSelectorUsage(e,l),l[0]}_queryNth(e,i){const r=[...e];let l=+i.body;return l===-1&&(l=r.length-1),new Set(r.slice(l,l+1))}_queryLayoutSelector(e,i,r){const l=i.name,o=i.body,u=[],f=this.querySelectorAll(o.parsed,r);for(const d of e){const g=vv(l,d,f,o.distance);g!==void 0&&u.push({element:d,score:g})}return u.sort((d,g)=>d.score-g.score),new Set(u.map(d=>d.element))}ariaSnapshot(e,i){return this.incrementalAriaSnapshot(e,i).full}incrementalAriaSnapshot(e,i){if(e.nodeType!==Node.ELEMENT_NODE)throw this.createStacklessError("Can only capture aria snapshot of Element nodes.");const r=Pa(e,i),l=Ja(r,i);let o;if(i.track){const u=this._lastAriaSnapshotForTrack.get(i.track);u&&(o=Ja(r,i,u).text),this._lastAriaSnapshotForTrack.set(i.track,r)}return this._lastAriaSnapshotForQuery=r,{full:l.text,incremental:o,iframeRefs:r.iframeRefs,iframeDepths:l.iframeDepths}}ariaSnapshotForRecorder(){const e=Pa(this.document.body,{mode:"ai"}),{text:i}=Ja(e,{mode:"ai"});return{ariaSnapshot:i,refs:e.refs}}getAllElementsMatchingExpectAriaTemplate(e,i){return oT(e.documentElement,i)}querySelectorAll(e,i){if(e.capture!==void 0){if(e.parts.some(l=>l.name==="nth"))throw this.createStacklessError("Can't query n-th element in a request with the capture.");const r={parts:e.parts.slice(0,e.capture+1)};if(e.capturer.has(u)))}else if(l.name==="internal:or"){const o=this.querySelectorAll(l.body.parsed,i);r=new Set(xv(new Set([...r,...o])))}else if(vT.includes(l.name))r=this._queryLayoutSelector(r,l,i);else{const o=new Set;for(const u of r){const f=this._queryEngineAll(l,u);for(const d of f)o.add(d)}r=o}return[...r]}finally{this._evaluator.end()}}_queryEngineAll(e,i){const r=this._engines.get(e.name).queryAll(i,e.body);for(const l of r)if(!("nodeName"in l))throw this.createStacklessError(`Expected a Node but got ${Object.prototype.toString.call(l)}`);return r}_createAttributeEngine(e,i){const r=l=>[{simples:[{selector:{css:`[${e}=${JSON.stringify(l)}]`,functions:[]},combinator:""}]}];return{queryAll:(l,o)=>this._evaluator.query({scope:l,pierceShadow:i},r(o))}}_createCSSEngine(){return{queryAll:(e,i)=>this._evaluator.query({scope:e,pierceShadow:!0},i)}}_createTextEngine(e,i){return{queryAll:(l,o)=>{const{matcher:u,kind:f}=Uo(o,i),d=[];let g=null;const b=S=>{if(f==="lax"&&g&&g.contains(S))return!1;const w=wc(this._evaluator._cacheText,S,u);w==="none"&&(g=S),(w==="self"||w==="selfAndChildren"&&f==="strict"&&!i)&&d.push(S)};l.nodeType===Node.ELEMENT_NODE&&b(l);const m=this._evaluator._queryCSS({scope:l,pierceShadow:e},"*");for(const S of m)b(S);return d}}}_createInternalHasTextEngine(){return{queryAll:(e,i)=>{if(e.nodeType!==1)return[];const r=e,l=Vt(this._evaluator._cacheText,r),{matcher:o}=Uo(i,!0);return o(l)?[r]:[]}}}_createInternalHasNotTextEngine(){return{queryAll:(e,i)=>{if(e.nodeType!==1)return[];const r=e,l=Vt(this._evaluator._cacheText,r),{matcher:o}=Uo(i,!0);return o(l)?[]:[r]}}}_createInternalLabelEngine(){return{queryAll:(e,i)=>{const{matcher:r}=Uo(i,!0);return this._evaluator._queryCSS({scope:e,pierceShadow:!0},"*").filter(o=>Sv(this._evaluator._cacheText,o).some(u=>r(u)))}}}_createNamedAttributeEngine(){return{queryAll:(i,r)=>{const l=Xa(r);if(l.name||l.attributes.length!==1)throw new Error("Malformed attribute selector: "+r);const{name:o,value:u,caseSensitive:f}=l.attributes[0],d=f?null:u.toLowerCase();let g;return u instanceof RegExp?g=m=>!!m.match(u):f?g=m=>m===u:g=m=>m.toLowerCase().includes(d),this._evaluator._queryCSS({scope:i,pierceShadow:!0},`[${o}]`).filter(m=>g(m.getAttribute(o)))}}}_createDescribeEngine(){return{queryAll:i=>i.nodeType!==1?[]:[i]}}_createControlEngine(){return{queryAll(e,i){if(i==="enter-frame")return[];if(i==="return-empty")return[];if(i==="component")return e.nodeType!==1?[]:[e.childElementCount===1?e.firstElementChild:e];throw new Error(`Internal error, unknown internal:control selector ${i}`)}}}_createHasEngine(){return{queryAll:(i,r)=>i.nodeType!==1?[]:!!this.querySelector(r.parsed,i,!1)?[i]:[]}}_createHasNotEngine(){return{queryAll:(i,r)=>i.nodeType!==1?[]:!!this.querySelector(r.parsed,i,!1)?[]:[i]}}_createVisibleEngine(){return{queryAll:(i,r)=>{if(i.nodeType!==1)return[];const l=r==="true";return Di(i)===l?[i]:[]}}}_createInternalChainEngine(){return{queryAll:(i,r)=>this.querySelectorAll(r.parsed,i)}}extend(e,i){const r=this.window.eval(` - (() => { - const module = {}; - ${e} - return module.exports.default(); - })()`);return new r(this,i)}async viewportRatio(e){return await new Promise(i=>{const r=new IntersectionObserver(l=>{i(l[0].intersectionRatio),r.disconnect()});r.observe(e),this.utils.builtins.requestAnimationFrame(()=>{})})}getElementBorderWidth(e){if(e.nodeType!==Node.ELEMENT_NODE||!e.ownerDocument||!e.ownerDocument.defaultView)return{left:0,top:0};const i=e.ownerDocument.defaultView.getComputedStyle(e);return{left:parseInt(i.borderLeftWidth||"",10),top:parseInt(i.borderTopWidth||"",10)}}describeIFrameStyle(e){if(!e.ownerDocument||!e.ownerDocument.defaultView)return"error:notconnected";const i=e.ownerDocument.defaultView;for(let l=e;l;l=xt(l))if(i.getComputedStyle(l).transform!=="none")return"transformed";const r=i.getComputedStyle(e);return{left:parseInt(r.borderLeftWidth||"",10)+parseInt(r.paddingLeft||"",10),top:parseInt(r.borderTopWidth||"",10)+parseInt(r.paddingTop||"",10)}}retarget(e,i){let r=e.nodeType===Node.ELEMENT_NODE?e:e.parentElement;if(!r)return null;if(i==="none")return r;if(!r.matches("input, textarea, select")&&!r.isContentEditable&&(i==="button-link"?r=r.closest("button, [role=button], a, [role=link]")||r:r=r.closest("button, [role=button], [role=checkbox], [role=radio]")||r),i==="follow-label"&&!r.matches("a, input, textarea, button, select, [role=link], [role=button], [role=checkbox], [role=radio]")&&!r.isContentEditable){const l=r.closest("label");l&&l.control&&(r=l.control)}return r}async checkElementStates(e,i){if(i.includes("stable")){const r=await this._checkElementIsStable(e);if(r===!1)return{missingState:"stable"};if(r==="error:notconnected")return"error:notconnected"}for(const r of i)if(r!=="stable"){const l=this.elementState(e,r);if(l.received==="error:notconnected")return"error:notconnected";if(!l.matches)return{missingState:r}}}async _checkElementIsStable(e){const i=Symbol("continuePolling");let r,l=0,o=0;const u=()=>{const m=this.retarget(e,"no-follow-label");if(!m)return"error:notconnected";const S=this.utils.builtins.performance.now();if(this._stableRafCount>1&&S-o<15)return i;o=S;const w=m.getBoundingClientRect(),T={x:w.top,y:w.left,width:w.width,height:w.height};if(r){if(!(T.x===r.x&&T.y===r.y&&T.width===r.width&&T.height===r.height))return!1;if(++l>=this._stableRafCount)return!0}return r=T,i};let f,d;const g=new Promise((m,S)=>{f=m,d=S}),b=()=>{try{const m=u();m!==i?f(m):this.utils.builtins.requestAnimationFrame(b)}catch(m){d(m)}};return this.utils.builtins.requestAnimationFrame(b),g}_createAriaRefEngine(){return{queryAll:(i,r)=>{var o,u;const l=(u=(o=this._lastAriaSnapshotForQuery)==null?void 0:o.elements)==null?void 0:u.get(r);return l&&l.isConnected?[l]:[]}}}elementState(e,i){const r=this.retarget(e,["visible","hidden"].includes(i)?"none":"follow-label");if(!r||!r.isConnected)return i==="hidden"?{matches:!0,received:"hidden"}:{matches:!1,received:"error:notconnected"};if(i==="visible"||i==="hidden"){const l=Di(r);return{matches:i==="visible"?l:!l,received:l?"visible":"hidden"}}if(i==="disabled"||i==="enabled"){const l=uc(r);return{matches:i==="disabled"?l:!l,received:l?"disabled":"enabled"}}if(i==="editable"){const l=uc(r),o=PE(r);if(o==="error")throw this.createStacklessError("Element is not an ,