FE
FDE·RESEARCH

数据 API 化方案

从 JS 数组到 SQLite + REST API — 支持本地维护、第三方开放、ref 元数据返工

作者:zxb 范围:77 条案例 + 13 张分析图 预计周期:6 周

01 现状摸底

当前所有数据硬编码在 site/assets/js/cases-data.js 和 analysis-data.js 两个 JS 文件里。下面是 77 条案例的完整画像。

77
案例总数
17
行业分类
3
大区(亚/欧/美)
60+
引用域名

行业分布 Top 8

地区分布

规模分布

发布年分布

改造点

cat 用短码(mfg/entai)需要字典映射 · ref.url 在 60+ 域名上无元数据需返工 · 长文本/数组结构不统一

02 数据库结构

基于数据画像,设计 7 张表。主表只存元数据,长文本/数组拆表,字典外键管理。

表结构总览

表名用途行级数据
cases主表,一行=一个案例id / num / title / industry / region / kpi ...
refs引用表,一对多,★ 返工目标url / title / author / published_at / type / language
demands需求列表(数组拆表)case_id / ord / body
processes流程列表(数组拆表)case_id / ord / body
compare_cells对比表二维case_id / ord / col0 / col1 / col2
tags + case_tags标签字典 + 多对多name / case_id ↔ tag_id
sources + case_sources信源类型字典(信任度)name / trust 1-5

核心 Schema (SQLite)

-- 主表
CREATE TABLE cases (
  id TEXT PRIMARY KEY,              -- 'tampa'
  num TEXT NOT NULL,                -- '08'
  slug TEXT UNIQUE,                 -- URL 友好
  title TEXT NOT NULL,
  subtitle TEXT,
  industry TEXT NOT NULL,           -- '医疗' 显示用
  cat TEXT NOT NULL,                -- 'med' 短码
  scale TEXT NOT NULL,
  type TEXT,
  region TEXT NOT NULL,             -- '亚洲' | '北美' | '欧洲'
  country CHAR(2),                  -- ISO 3166-1 alpha-2
  year INTEGER,
  month INTEGER,
  intro_name TEXT,
  intro_desc TEXT,                  -- 长文本
  result TEXT,                      -- 长文本
  cover_css TEXT,                   -- linear-gradient(...)
  cover_img TEXT,
  highlight TEXT,
  kpi_value REAL,
  kpi_unit TEXT,
  kpi_label TEXT,
  published_at DATE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  verified_by TEXT
);
CREATE INDEX idx_cases_year ON cases(year);
CREATE INDEX idx_cases_region ON cases(region);
CREATE INDEX idx_cases_cat ON cases(cat);

-- 引用表(返工目标)
CREATE TABLE refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  case_id TEXT NOT NULL REFERENCES cases(id) ON DELETE CASCADE,
  ord INTEGER DEFAULT 0,
  url TEXT NOT NULL,
  label TEXT,
  title TEXT,                       -- ★ 待返工
  author TEXT,                      -- ★ 待返工
  published_at DATE,                -- ★ 待返工
  publisher TEXT,                   -- ★ 待返工
  type TEXT,                        -- article | press-release | blog | paper | tweet
  language CHAR(2),
  fetched_at TIMESTAMP,
  verified INTEGER DEFAULT 0
);

设计要点

03 项目结构

不建议改 Monorepo。静态站和 API 部署频率不同,前端零成本部署到 CDN,API 独立部署。保留 Monorepo 迁移路径:schema/ 目录放共用 TS 类型。

# 暂不 Monorepo,后续可平滑迁移 fd-go/ ├── site/ # 静态前端,HTML+CSS+Vanilla JS,零框架 │ ├── pages/ │ └── assets/js/ # 改用 fetch('/api/v1/cases') │ ├── schema/ # 新增,纯 TS 类型 + Zod 校验,前后端共用 │ └── case.ts │ ├── data/ # 新增,数据源 │ ├── fde.sqlite # 主库(git LFS 或独立发布) │ ├── schema.sql # 建表脚本 │ └── seed/ # 一次性原始材料 │ ├── tools/ # 一次性任务脚本 │ ├── migrate-from-js.js # Node: JS → SQLite │ ├── enrich-refs.py # Python: 抓 ref 元数据 │ └── gen-covers-*.js # minimax 封面生成 │ ├── api/ # 新增,后端 │ ├── src/ │ │ ├── index.ts # Hono 入口 │ │ ├── routes/ │ │ │ ├── cases.ts │ │ │ ├── refs.ts │ │ │ └── stats.ts │ │ ├── db.ts # better-sqlite3 │ │ └── middleware/ │ └── package.json │ └── docs/ # 方案文档 + API 文档(OpenAPI 自动生成)

04 技术选型

前端

保留 HTML / CSS / Vanilla JS

当前 77 条数据 + 13 张图,首屏快、SEO 好。引入 React/Vue = 重新写所有交互 + 构建工具链。数据通过 fetch('/api/v1/cases') 拿,逻辑零改动。

后端 — 三方案对比

Node.js + Express

  • 生态成熟
  • 社区资源最多
  • 配置繁琐
  • 类型推断一般
  • 中间件冗余

Python + FastAPI

  • 数据处理/爬虫生态最强
  • 自动 OpenAPI
  • 前后端 TS 类型不同步
  • 需部署 Python 运行时

数据库 — 双轨

环境数据库理由
本地开发SQLite 文件单文件零部署,77 条性能绰绰有余
生产部署Cloudflare D1边缘部署,免费 10 万请求/天,与 SQLite SQL 方言 99% 兼容
备选VPS + SQLiteD1 不够用时迁 VPS,迁移成本 1 天

数据返工 — Python

你的需求里"抓 ref 元数据"Python 生态最强:trafilatura / metascraper / httpx / beautifulsoup4。

推荐双语言:API 服务用 Node.js + TS,数据返工用 Python。

05 API 路由设计

REST 路由

方法路径说明
GET/api/v1/cases列表,支持 ?region=&year=&cat=&q=&limit=&offset=
GET/api/v1/cases/:id单条详情(包含 demands/processes/compare)
GET/api/v1/cases/:id/refs该案例的引用列表
GET/api/v1/categories行业字典
GET/api/v1/regions地区字典
GET/api/v1/stats/overview总览
GET/api/v1/stats/by-region地区分布
GET/api/v1/stats/by-industry行业分布
GET/api/v1/stats/by-month月度时间序列
GET/api/v1/health健康检查

输出规范

{
  "data": [...],
  "meta": { "total": 77, "limit": 20, "offset": 0 },
  "links": { "next": "/api/v1/cases?offset=20" }
}

调用示例

# 列表,筛选 2025 年亚太区的企业 AI 案例
curl 'https://api.fd-go.com/v1/cases?year=2025®ion=%E4%BA%9A%E6%B4%B2&cat=entai'

# 单条详情
curl https://api.fd-go.com/v1/cases/tampa

# 案例的引用
curl https://api.fd-go.com/v1/cases/tampa/refs

06 改造路径(分阶段,不爆雷)

Week 1
Phase 1: schema.sql + 迁移脚本读 cases-data.js → 写 SQLite → 重新生成 cases-data.js
数据层
Week 2
Phase 2 启动: Hono 骨架 + /cases 列表接口本地启动 API,curl 验证
API
Week 3
Phase 2 收尾: 详情 / 字典 / 统计接口 + OpenAPISwagger UI 上线
API
Week 4
Phase 3: enrich-refs.py + 77 条 ref 元数据返工Python 批量抓取 + 人工兜底
数据
Week 5
Phase 4: 前端 fetch() 切换 + 部署到 CloudflareD1 数据库迁移,API 上线
集成
Week 6
第三方 API 文档发布 + 试运营rate limit + API key 接入
开放
不变更承诺

Phase 1 完成后,前端 0 行为差异 — 重新生成的 cases-data.js 与原版逐字段对比,完全一致才进入 Phase 2。

07 部署形态

模块部署目标成本
静态前端Cloudflare Pages / GitHub Pages免费,CDN 全球
API 服务Cloudflare Workers + D1免费 10 万请求/天
SQLite 文件Cloudflare R2 / Git LFS几美分/月
数据返工本地 Python0
回退方案

若 Cloudflare 不够用:API 迁到 VPS(DigitalOcean / 阿里云)+ Node 进程,SQLite 文件放 VPS,定期备份到 S3。迁移成本 1 天。

08 ref 元数据批处理

77 条引用了 60+ 域名,Top 来源:linkedin.com 10 篇 · openai.com 5 篇 · databricks.com 3 篇 · 中文新闻媒体若干。

返工脚本骨架

# tools/enrich-refs.py
import httpx, metascraper, sqlite3
from datetime import datetime

def enrich_url(url: str) -> dict:
    """抓 URL 元数据 → {title, author, published_at, publisher, language}"""
    html = httpx.get(url, follow_redirects=True).text
    meta = metascraper.scrape(url=url, html=html)
    return {
        'title':        meta.get('title'),
        'author':       meta.get('author'),
        'published_at': meta.get('published_date'),
        'publisher':    meta.get('publisher') or meta.get('site_name'),
        'language':     'zh' if is_chinese(meta.get('title','')) else 'en',
    }

db = sqlite3.connect('data/fde.sqlite')
for ref_id, url in db.execute(
    "SELECT id, url FROM refs WHERE title IS NULL"):
    try:
        meta = enrich_url(url)
        db.execute("""UPDATE refs SET
            title=?, author=?, published_at=?, publisher=?,
            language=?, fetched_at=? WHERE id=?""",
            [*meta.values(), datetime.now(), ref_id])
        print(f'OK #{ref_id}: {meta["title"][:50]}')
    except Exception as e:
        print(f'FAIL #{ref_id}: {e}')
db.commit()

预期

09 LLM 接入策略

未来 LLM(Claude / GPT / 自定义 Agent)会大量查询我们的数据。两种形式互补,不冲突:md/json 适合快照/RAG,API 适合实时/查询。

主通道 vs 辅助通道

md / json dump

  • LLM 直接吃,token 友好
  • 结构清晰,人类也能读
  • 适合 RAG / 向量检索
  • 导出后离线分析
  • 快照,无法保证新鲜
  • 1w 条 md ≈ 50MB,context window 爆
  • 不能按 region 筛选后再读

MCP (Model Context Protocol) — 2026 新趋势

Anthropic 推的 MCP 是 LLM-first API 标准,把 API 直接变成 LLM 可调用的工具。一次集成,所有 MCP-兼容 LLM(Claude / Cursor / 自定义)都能用。

# 同一份代码,两套入口 LLM ─┬─→ MCP Server ─┐ └─→ REST Client ─┴─→ Hono API ─→ Postgres / SQLite

API 的 LLM 友好性要求

要求原因
/openapi.json 完整 schemaLLM 看 schema 才知道怎么调
返回字段精简不要把 1000 字 introDesc 塞进列表 API
支持 ?fields= 过滤LLM 只需要 title+highlight 时别返 process[]
支持 ?include= 展开默认只返元数据,详情才展开
分页强制?limit=20&cursor=...,防 LLM 一次拉 1w 条
错误信息具体"field year must be 2020-2026" 这种

API 路由 — 增 LLM 端点

GET    /api/v1/cases                     # 人类用,完整字段
GET    /api/v1/llm/cases                 # LLM 用,精简字段
                                        #   ?include=summary,keywords
                                        #   ?max_tokens=2000 自动截断
GET    /api/v1/llm/cases/:id/summary     # LLM 看单条摘要
GET    /api/v1/llm/search?q=xxx          # LLM 语义检索入口
GET    /api/v1/openapi.json              # 自动生成,LLM 看 schema

Schema 加 LLM-friendly 字段(为未来预留)

ALTER TABLE cases ADD COLUMN summary TEXT;
  -- 一句话摘要(LLM 检索第一眼看这个)
ALTER TABLE cases ADD COLUMN keywords TEXT[];
  -- 关键词数组(LLM/RAG 检索用)
ALTER TABLE cases ADD COLUMN embedding vector(1536);
  -- pgvector,后续做语义检索
导出频率建议

md/json dump 每周一次 + 每次大量更新后。脚本:tools/export-llm-corpus.py,输出到 data/exports/ 目录(R2 公开访问)。

10 1 万条规模扩展

从 77 条到 1 万条(130 倍),很多"轻量"假设会失效。

必须改的项

项77 条(当前)1 万条改动
数据库SQLite OKPostgres 才是答案改
前端 fetch一次性 77 条,合理1 万条 50KB+,SEO 爆改
部署Workers + D1D1 5GB 上限不够改
数据返工一次性脚本必须后台 + 队列改
检索LIKE 模糊全文 + 向量改
后台手改 JS必须有管理后台改

数据库:SQLite → Postgres / Supabase

SQLite 在 1w 条会出问题:1GB 软上限 + 无并发写 + 无内建全文检索。Postgres / Supabase 解法:

  • 单库 TB 级,1w 条小意思
  • 并发读写,后台多人同时编辑不冲突
  • 内建 tsvector 全文检索,中文用 zhparser
  • pgvector 后续做语义检索

前端:Vanilla JS → Next.js SSR / ISR

阶段方案适用数据量
当前静态 HTML + fetch< 200 条
中期SSR + ISR(Next.js)1 千 ~1 万
远期SSR + 分页 API + 全文检索10 万+

1 万条架构图

# 1 万条规模 ┌──────────────────────────────────────────────────────────┐ │ │ │ 用户 ─→ CDN / Vercel Edge │ │ ↓ │ │ Next.js 14 (App Router) │ │ ├ / 首页 (静态 SSG) │ │ ├ /cases 列表 (SSR + ISR 60s) │ │ ├ /case/[slug] (SSR + ISR 1h) │ │ └ /admin/* (Refine 后台) │ │ ↓ │ │ Hono / Next.js API Route │ │ ├ 缓存层 (Vercel KV / Redis) │ │ └ 业务逻辑 │ │ ↓ │ │ Supabase Postgres │ │ ├ cases (主表) │ │ ├ refs (引用) │ │ └ + FTS 索引 │ │ ↑ │ │ Refine 后台 (案例编辑) │ │ ↑ │ │ Python 返工队列 (cron + retry) │ └──────────────────────────────────────────────────────────┘

真实成本预估 (1 万条)

模块服务成本
PostgresSupabase Pro$25/月
API + 前端Vercel Pro$20/月
图床Cloudflare R2~$1/月
总计~$50/月
分阶段路线(推荐)

现在 ~ 500 条:保持当前架构 + 引入 Postgres/Supabase + Drizzle schema,前端零改动。 · 500~5000:加 Supabase Studio 后台 + 全文检索 + ISR。 · 5000~1w:迁 Next.js SSR + Refine + pgvector。每个阶段改动量最小。

11 风险与决策点

风险应对
数据迁移丢失Phase 1 后 diff 工具对比新旧数据完整性
API 上线后前端崩溃保留 cases-data.js 作为 fallback
Cloudflare D1 配额不够备用 VPS,迁移成本 1 天
ref 元数据抓不准留 verified=0 字段,人工兜底
第三方滥用 APIrate limit + API key + 使用条款

12 下一步

需要你决策的点
  • 数据库:SQLite + D1 (推荐) vs Postgres + 自建服务
  • API 框架:Hono (推荐) vs Express vs FastAPI
  • 部署目标:Cloudflare (推荐,免费) vs 自建 VPS vs 其他
  • 数据返工:要不要现在就写一版 enrich-refs.py 原型试跑 10 条?
Phase 1 待办(本方案通过后启动)
  1. 写 data/schema.sql
  2. 写 tools/migrate-from-js.js(读 cases-data.js → 写 SQLite)
  3. 写 tools/build-cases-data.js(读 SQLite → 重新生成 cases-data.js)
  4. 用 Drizzle schema 定义 TypeScript 类型(前后端共用)

完整 Markdown 文档:docs/architecture/api-architecture-proposal.md