Doramagic 项目包 · 项目说明书

portaljs 项目

AI 原生框架,用于构建数据门户。只需一份简要说明,即可借助 agentic 技能在数分钟内搭建完整门户并接入数据集,支持任意后端(CKAN、GitHub、Frictionless)。

概览与快速上手

PortalJS 是一个面向开放数据生态的现代化数据门户(data portal)框架,由 Datopian 维护。它由原先的 Recline.js 演进而来,目标是为数据集浏览、可视化与发布提供一个可组合、可扩展的前端栈。

章节 相关页面

继续阅读本节完整说明和来源证据。

项目定位与生态

PortalJS 将自身定位为「数据门户框架」而非单一应用,强调与既有 CKAN 等数据后端的互操作性。社区 FAQ 明确指出:PortalJS Cloud 构建于 CKAN 的 API 之上,迁移后所有标准 CKAN 端点继续工作,前端升级而数据层不变 资料来源:README.md:1-40

维度设计取向
框架角色数据门户前端,而非数据探索器
后端耦合默认对接 CKAN,提供 @portaljs/ckan-api-client-js
渲染栈基于 React / Next.js,组件化交付
扩展点Agentic Skills(/portaljs-*) + 可插拔组件库

资料来源:VISION.md:1-30README.md:20-60

核心包结构

仓库采用 monorepo 组织,主要发布物包括:

  • packages/create-portaljs:脚手架,使用 npm create portaljs@latest 一键生成新门户 资料来源:packages/create-portaljs/README.md:1-25]。
  • @portaljs/components:可视化与展示组件库,已发布至 1.2.x(含 LineChart、Map 等) 资料来源:README.md:80-120
  • @portaljs/ckan-api-client-js:首次公开版本为 1.4.0,用于与 CKAN API 交互 资料来源:README.md:120-150

快速上手流程

  1. 脚手架生成项目:在终端运行 npm create portaljs@latest,CLI 会引导选择模板与配置 资料来源:packages/create-portaljs/index.mjs:1-80
  2. 启动示例:进入生成的目录,安装依赖并执行 npm run devexamples/portaljs-catalog 提供了一个完整的目录门户示例可供参考 资料来源:examples/portaljs-catalog/README.md:1-40
  3. 连接到数据源:通过 ckan-api-client-js 配置 CKAN endpoint URL,即可复用既有数据集,无需迁移数据层 资料来源:README.md:40-80
  4. 路由更新:从 0.2.x 升级到 0.3.0 之后,create-portaljs 在创建过程中展示了品牌化的「cyclone」动画提示(青蓝渐变、旋转状态图标),用于引导用户关注后续步骤 资料来源:packages/create-portaljs/index.mjs:80-160

Agentic Skills 与后续扩展

[email protected] 起,CLI 会将 PortalJS 的「agentic skills」打包到项目的 .claude/ 目录;从 0.6.0 起,技能统一采用 portaljs- 前缀,例如:

  • /portaljs-new-portal:引导新建门户的交互式流程。
  • /portaljs-add-dataset:向现有门户追加数据集条目。
  • /portaljs-add-chart:在数据集页中加入可视化。
  • /migrate(0.5.0 引入):从遗留来源抓取并打包数据集 资料来源:packages/create-portaljs/index.mjs:160-260

这些技能使开发者可在不离开编辑环境的情况下完成常见的数据门户操作,呼应了 ROADMAP 中「以可组合工具替代一次性脚手架」的方向 资料来源:ROADMAP.md:1-50

已知注意事项

  • LineChart 缺值:1.2.3 起版本会在缺失或无效数值处断开连线,避免把离散的点错误连成一条折线 资料来源:README.md:150-180]。
  • Map 组件 tileLayerName:自 1.2.1 起为可选参数,未提供时不报错 资料来源:README.md:180-210]。
  • 外部依赖xlsx 在公共 npm registry 中版本过时(最旧仅到 0.18.5),推荐使用 https://cdn.sheetjs.com/ 官方源 资料来源:README.md:210-240]。
  • remark-wiki-link:在使用 wiki link 插件时若遇到 Cannot read properties of undefined (reading 'data'),需确认上游数据节点非空后再调用 资料来源:README.md:240-260
  • 数据源 URL:托管在 datahub.io 上的 CSV/资源链接(如 un-locode)可能在迁移后 404,应改用最新地址或在迁移脚本中做好回退 资料来源:README.md:260-280

通过以上步骤,开发者可在数分钟内拉起一个具备 CKAN 数据接入、可视化与扩展技能的数据门户,并按需演进为生产部署。

资料来源:VISION.md:1-30README.md:20-60

系统架构与数据流

PortalJS 是由 Datopian 维护的现代化开放数据门户框架,前身为 Recline.js。其核心目标是从单纯的"数据浏览器"演进为完整的数据门户框架,覆盖数据集检索、可视化与发布全流程。整体架构遵循"前端薄壳、后端解耦"的原则:前端通过抽象的 Provider 接口与数据源解耦,从而同时支持静态离线门户、托管部署以及与 PortalJS Cloud(基于 CKA...

章节 相关页面

继续阅读本节完整说明和来源证据。

概述与设计目标

PortalJS 是由 Datopian 维护的现代化开放数据门户框架,前身为 Recline.js。其核心目标是从单纯的"数据浏览器"演进为完整的数据门户框架,覆盖数据集检索、可视化与发布全流程。整体架构遵循"前端薄壳、后端解耦"的原则:前端通过抽象的 Provider 接口与数据源解耦,从而同时支持静态离线门户、托管部署以及与 PortalJS Cloud(基于 CKAN)的无缝迁移。资料来源:DESIGN.md

核心包结构与模块职责

仓库采用 monorepo 形式组织,核心包职责清晰:

  • @portaljs/components:React 组件库,提供 LineChart、Map、PDF 等可视化与交互组件。LineChart 会在缺失值处自动断线,xAxisTimeUnit 支持 yearmonth 等粒度;Map 组件的 tileLayerName 为可选项。资料来源:DESIGN.md
  • @portaljs/ckan-api-client-js:CKAN API 的 JS 客户端封装,于 v1.4.0 正式公开发布,使前端能以一致方式调用 CKAN 后端。资料来源:DESIGN.md
  • create-portaljs:脚手架工具,支持通过 npm create portaljs@latest 一键创建门户项目;自 v0.4.0 起将 portaljs- 前缀的代理技能打包进 .claude/ 目录,方便 AI 辅助开发。资料来源:DESIGN.md

数据流与 Provider 抽象层

数据流的核心是 providers 抽象层。所有数据集访问都通过统一的 IProvider 接口进行,屏蔽底层数据源差异,使上层 UI 不关心数据来自本地文件、CKAN API 还是其他后端。资料来源:examples/portaljs-catalog/lib/providers/types.ts

providers/index.ts 通过工厂模式导出默认 Provider 实例,UI 层仅依赖该单例,便于在不同部署模式下替换实现。资料来源:examples/portaljs-catalog/lib/providers/index.ts

static-provider.ts 实现了基于本地文件系统的 Provider,用于离线、演示或构建期场景,直接读取项目内 data/ 目录的资源并以 Frictionless 协议返回。资料来源:examples/portaljs-catalog/lib/providers/static-provider.ts

元数据层与 Frictionless 适配

元数据层位于 lib/metadata/,负责将原始数据文件解析为标准化的 Dataset 模型,供上层组件消费。资料来源:examples/portaljs-catalog/lib/metadata/index.ts

frictionless-tabular.ts 实现对 Frictionless Data Package 规范的解析,将 CSV、TSV 等表格资源转换为字段、类型与 schema 信息。这一层使 UI 组件能够自动推断列类型并渲染图表,避免硬编码。资料来源:examples/portaljs-catalog/lib/metadata/frictionless-tabular.ts

端到端数据流图

flowchart LR
  A[用户浏览器] --> B[Next.js 前端]
  B --> C[Provider 抽象层]
  C --> D[Static Provider]
  C --> E[CKAN API Client]
  D --> F[本地 Frictionless 包]
  E --> G[CKAN 后端 / PortalJS Cloud]
  F --> H[Metadata 解析层]
  G --> H
  H --> I[Components 渲染<br/>LineChart/Map/PDF]

社区关注点与架构演进

社区反馈显示框架正持续向最新 Next.js 与 App Router 迁移以提升性能,并修复了 PDF 组件缺失的 CSS 样式。资料来源:DESIGN.md

在数据迁移方面,[email protected] 引入了 /migrate 技能,可采集 CKAN 站点数据集并迁移到本地门户,进一步强化了 Provider 抽象的实用性。资料来源:DESIGN.md

CKAN API 兼容性是架构决策的关键:PortalJS Cloud 基于 CKAN API 构建,所有标准端点在迁移后保持可用,前端变化不影响数据层集成。资料来源:DESIGN.md

来源:https://github.com/datopian/portaljs / 项目说明书

代理技能与 AI 集成

PortalJS 通过仓库根目录下的 .claude-plugin/ 与 .claude/ 两套目录,把一组"代理技能"(agentic skills) 打包进 CLI 与脚手架,使 AI 助手(Claude 等)能够以斜杠命令的方式直接生成、改造并迁移数据门户代码。这套集成由 Datopian 主导,目的是把"自然语言 → PortalJS 项目"的链路标准化、版本化。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 安装路径

继续阅读本节完整说明和来源证据。

章节 创作规范

继续阅读本节完整说明和来源证据。

章节 典型 AI 辅助流程

继续阅读本节完整说明和来源证据。

概述与设计目标

PortalJS 通过仓库根目录下的 .claude-plugin/.claude/ 两套目录,把一组"代理技能"(agentic skills) 打包进 CLI 与脚手架,使 AI 助手(Claude 等)能够以斜杠命令的方式直接生成、改造并迁移数据门户代码。这套集成由 Datopian 主导,目的是把"自然语言 → PortalJS 项目"的链路标准化、版本化。

核心能力要点:

  • npm create portaljs@latest 启动的脚手架在生成项目时会把代理技能一并写入本地 .claude/commands/ 目录 资料来源:[email protected] release notes
  • 所有正式发布的技能统一使用 portaljs- 前缀,便于在 Claude 市场中识别与分类 资料来源:[email protected] release notes
  • CLI 启动时展示 sky→teal 渐变、旋转状态点与旋转图标的品牌动画,为 AI 协助场景营造一致的视觉反馈 资料来源:[email protected] release notes

插件清单与市场发布

.claude-plugin/plugin.json 用于声明插件元数据,包含名称、版本、技能清单与入口命令等字段,Claude 加载时会读取该文件来注册可用的斜杠命令 资料来源:.claude-plugin/plugin.json.claude-plugin/marketplace.json 则把该插件登记到 Claude Marketplace,使用户能通过市场发现并一键安装 PortalJS 技能套件 资料来源:.claude-plugin/marketplace.json

这种"plugin + marketplace"双层结构支持两条分发路径:

  1. 本地开发者把技能直接放进仓库 .claude/,随项目一起分发 资料来源:.claude/INSTALL.md
  2. 终端用户从市场单独获取 CLI,而不必克隆整个 monorepo 资料来源:.claude-plugin/marketplace.json

技能套件结构

每个代理技能对应 .claude/commands/ 下的一个 Markdown 提示词文件,文件名即斜杠命令名。当前随包发布的技能至少包含:

命令用途
/portaljs-new-portal从零搭建 PortalJS 数据门户
/portaljs-architect让 AI 充当 PortalJS 架构师,给出现有项目的改造建议
/portaljs-migrate把外部数据集收割并转换到新门户
/portaljs-add-dataset向现有门户添加新数据集
/portaljs-add-chart在数据集页面追加可视化图表

资料来源:[email protected] release notes、[email protected] release notes、.claude/commands/portaljs-new-portal.md.claude/commands/portaljs-architect.md

v0.6.0 之前这些命令曾以不同命名散布;该版本将技能套件统一改用 portaljs- 前缀,以消除歧义并提升市场中的可发现性。/migrate 技能则在 v0.5.0 中被打包进脚手架,使新项目从第一天起就具备数据迁移能力 资料来源:[email protected] release notes。

安装、创作与典型工作流

安装路径

.claude/INSTALL.md 给出两种安装方式:脚手架隐式安装(npm create portaljs@latest 把技能文件直接拷贝到新项目 .claude/commands/)和 Marketplace 显式安装(仅获取 CLI,可在任意目录触发斜杠命令)资料来源:.claude/INSTALL.md

创作规范

.claude/AUTHORING.md 为贡献者提供模板,说明如何撰写命令的 Markdown 描述、声明所需依赖(如 ckan-api-client-js),以及用版本号字段与 npm release 保持同步 资料来源:.claude/AUTHORING.md

典型 AI 辅助流程

flowchart LR
  A[用户在 Claude 中输入 /portaljs-new-portal] --> B[加载 .claude/commands/portaljs-new-portal.md 提示词]
  B --> C{项目是否存在?}
  C -- 否 --> D[调用 create-portaljs CLI 生成脚手架]
  C -- 是 --> E[读取现有 .claude/commands 与 package.json]
  D --> F[写入 .claude/commands 下的技能文件]
  E --> F
  F --> G[AI 按提示词修改或扩展源码]
  G --> H[用户确认后运行 npm run dev]

资料来源:.claude/INSTALL.md.claude/commands/portaljs-new-portal.md.claude/commands/portaljs-migrate.md

限制与注意事项

  • 技能套件与 CLI 版本强耦合:升级 create-portaljs 时应同步更新 .claude/ 目录,否则可能出现提示词引用了已被弃用的依赖(如旧版 [email protected])资料来源:issue #819
  • 部分数据集源 URL 会失效(如 datahub.io/core/un-locode 的 404 问题),AI 在调用 /portaljs-migrate 时需先校验源 URL 可用性 资料来源:issue #1095
  • Markdown 维基链接处理依赖 remark-wiki-link 插件,升级 Node 或 marked 解析器时需注意属性顺序 资料来源:issue #1059

资料来源:[email protected] release notes、[email protected] release notes、.claude/commands/portaljs-new-portal.md.claude/commands/portaljs-architect.md

后端集成、扩展与部署

PortalJS 的"后端集成、扩展与部署"围绕三个层级展开:CKAN 数据层对接、@portaljs/ckan-api-client-js 客户端封装层,以及基于 create-portaljs 脚手架与 packages/ckan 适配层的前端部署与扩展能力。下文按四个模块阐述。

章节 相关页面

继续阅读本节完整说明和来源证据。

CKAN 数据层与 PortalJS Cloud 兼容层

PortalJS 在数据层并不重新实现存储与目录系统,而是直接复用 CKAN 的 REST API。社区 FAQ 已明确:"PortalJS Cloud 构建在 CKAN 的 APIs 之上,迁移后所有标准 CKAN 端点继续工作,前端栈变更不影响数据层。"这意味着迁移、扩展与部署的关注点都集中在客户端封装和前端适配上,而非后端存储侧。资料来源:site/docs/core/ckan.md:1-40

在代码层面,@portaljs/ckan-api-client-js 把对 CKAN 端点的访问统一收敛到单一包中;其 1.4.0 版本作为初始公开发布版本,对外暴露若干高层方法用于读取 datasets、resources、organizations、tags 等对象。资料来源:packages/ckan-api-client-js/src/index.ts:1-80

CkanRequest 请求管线

CkanRequest 是与 CKAN 端点通信的核心类,统一处理 URL 构造、查询参数序列化、鉴权头(如 Authorization)注入,以及错误响应的结构化抛出。它位于 packages/ckan-api-client-js/src/CkanRequest.ts,被上层索引方法直接复用,使每个端点不必重复实现请求拼装。资料来源:packages/ckan-api-client-js/src/CkanRequest.ts:1-60

通过该抽象,PortalJS 既能在静态构建(如 Next.js SSG)场景下访问公共 CKAN 实例,也能在服务端组合鉴权调用私有实例,从而支撑自定义后端路由与中间件式集成。环境变量(如 CKAN_URLCKAN_API_KEY)通常在此层被读取并应用到请求头。资料来源:packages/ckan-api-client-js/src/CkanRequest.ts:60-120

前端 CKAN 适配层(packages/ckan)

packages/ckan 提供一组面向 CKAN 数据模型的 React 组件与 Hook,作为"前端适配层"将 CKAN 数据结构映射为列表、卡片、搜索表单等 UI 形态,统一通过 packages/ckan/src/index.ts 暴露。资料来源:packages/ckan/src/index.ts:1-40

packages/ckan/src/lib/ckanapi.tsx 进一步把上述原始请求封装为语义化辅助函数(如 searchDatasetsgetDataset),使上层页面组件不必感知 URL 拼接与翻页细节。资料来源:packages/ckan/src/lib/ckanapi.tsx:1-100

脚手架与扩展点:create-portaljs

create-portaljs 是面向终端用户的项目脚手架(npm create portaljs@latest),默认集成 Next.js(App Router)与 CKAN 客户端栈,可在 Vercel、Cloudflare、自托管 Node 等任意 Next.js 目标上完成生产部署。后续小版本持续强化扩展能力:

  • 0.3.0:引入品牌化 cyclone 启动动画,提升初始化反馈。资料来源:site/docs/create-portaljs.md:1-40
  • 0.4.0:将 PortalJS 的 agentic 技能(统一以 portaljs- 为前缀)打包进 .claude/,便于在 Claude 等代理工具内自动调用,如 /portaljs-new-portal/portaljs-add-dataset/portaljs-add-chart。资料来源:site/docs/create-portaljs.md:40-80
  • 0.5.0:新增 /portaljs-migrate 技能,可从既有 CKAN 实例收割数据集并生成对应代码,将存量门户平滑迁移至 PortalJS。资料来源:site/docs/create-portaljs.md:80-120
  • 0.6.0:将所有随包技能统一重命名为 portaljs- 前缀,形成稳定的代理扩展接口。资料来源:site/docs/create-portaljs.md:120-160

数据流与扩展点

flowchart LR
  A[CKAN 实例] -->|REST API| B(CkanRequest)
  B --> C[ckan-api-client-js]
  C --> D[ckanapi.tsx 辅助函数]
  D --> E[DatasetSearchForm / DatasetCard]
  E --> F[Next.js 页面]
  F --> G[create-portaljs 脚手架部署]
  H[.claude/ portaljs-* 技能] --> F
扩展点位置用途
鉴权与 URL 构造packages/ckan-api-client-js/src/CkanRequest.ts注入自定义请求头与基础 URL
端点封装packages/ckan-api-client-js/src/index.ts添加新的高层语义方法
数据适配packages/ckan/src/lib/ckanapi.tsx包装新的查询语义
列表/搜索 UIDatasetSearchForm.tsxDatasetCard.tsx复用或覆盖展示逻辑
代理技能create-portaljs .claude/注册新的 /portaljs-* 命令

社区关注点

社区反馈(issue #1618 中研究门户迁移、issue #1502 中 CKAN API 持续可用性)表明,用户在部署阶段最关心三件事:与既有 CKAN 实例的无缝兼容、迁移到 PortalJS Cloud 后 API 的向后兼容,以及通过技能机制在生成的脚手架内继续扩展的能力。资料来源:site/docs/core/ckan.md:1-40

来源:https://github.com/datopian/portaljs / 项目说明书

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 来源证据:Feedback on research.portaljs.com

可能增加新用户试用和生产接入成本。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

Pitfall Log / 踩坑日志

项目:datopian/portaljs

摘要:发现 9 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。

1. 配置坑 · 可能修改宿主 AI 配置

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
  • 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
  • 证据:capability.host_targets | https://github.com/datopian/portaljs | host_targets=claude_code, claude

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://github.com/datopian/portaljs | README/documentation is current enough for a first validation pass.

3. 运行坑 · 来源证据:Feedback on research.portaljs.com

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个运行相关的待验证问题:Feedback on research.portaljs.com
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 证据:community_evidence:github | https://github.com/datopian/portaljs/issues/1618 | 来源类型 github_issue 暴露的待验证使用条件。

4. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://github.com/datopian/portaljs | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://github.com/datopian/portaljs | no_demo; severity=medium

6. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://github.com/datopian/portaljs | no_demo; severity=medium

7. 安全/权限坑 · 来源证据:Add 6 new FAQs in FAQ page

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:Add 6 new FAQs in FAQ page
  • 对用户的影响:可能影响升级、迁移或版本选择。
  • 证据:community_evidence:github | https://github.com/datopian/portaljs/issues/1502 | 来源类型 github_issue 暴露的待验证使用条件。

8. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://github.com/datopian/portaljs | issue_or_pr_quality=unknown

9. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://github.com/datopian/portaljs | release_recency=unknown

来源:Doramagic 发现、验证与编译记录