内容
<p align="center">
<img src="apps/web/public/banner.png" alt="Enpal Pulse" />
</p>
<p align="center">
<a href="https://nextjs.org"><img src="https://img.shields.io/badge/Next.js-16-000000?style=flat-square&logo=next.js&logoColor=white" alt="Next.js" /></a>
<a href="https://docs.skybridge.tech"><img src="https://img.shields.io/badge/Skybridge-1.1.1-2563eb?style=flat-square&logo=react&logoColor=white" alt="Skybridge" /></a>
<a href="https://pulse.niklas.sh"><img src="https://img.shields.io/badge/Demo-pulse.niklas.sh-7c3aed?style=flat-square" alt="Live demo" /></a>
</p>
<p align="center">
<a href="https://www.loom.com/share/61196e8b7f1142ec9f03f0a67bd144f2"><strong>▶ 观看演示视频</strong></a>
</p>
Enpal Pulse 将一个家庭的太阳能生产、电池状态、热泵和电动汽车负荷、网格流动、动态关税和合同条款集中在一个地方。它是为 **Enpal 智能能源伴侣** 挑战而构建的,它以通俗的语言回答日常能源问题,并帮助您决定何时使用电力。
它作为同一个数据上的两个表面交付:
- **Next.js 仪表盘**,用于统一的能源视图。
- **Skybridge MCP 服务器**,具有交互式 React 视图,以便 LLM 在 ChatGPT 或 Claude 中可以对话式地推理相同的家庭数据。
## 演示
仪表盘上的统一能源视图:
<p align="center">
<img src="apps/web/public/demo-energy-flow.gif" alt="Daily energy flow on the dashboard" width="700" />
</p>
相同的家庭数据,在 Claude 中对话式推理:
<p align="center">
<img src="apps/web/public/demo-claude.gif" alt="Asking Claude about household energy via the MCP server" width="420" />
</p>
## 尝试
- **仪表盘:** [pulse.niklas.sh](https://pulse.niklas.sh)
- **MCP 服务器 URL:** `https://mcp.pulse.niklas.sh/mcp`
将 MCP 服务器 URL 添加到任何兼容的客户端(ChatGPT、Claude 等),然后询问诸如 _“为什么一月份的账单更高?”_ 、 _“我今天应该什么时候充电我的车?”_ 或 _“我的能源流动情况如何?”_ 之类的问题。
要连接 MCP 服务器:
- **ChatGPT** — 设置 → 连接器 → 添加上述 URL(开发者模式 / 自定义连接器)。
- **Claude** — 设置 → 连接器 → 添加自定义连接器 → 粘贴 URL。
## 工作原理
一个 Postgres 数据库保存完整的家庭数据集。两个表面生活在单个 **pnpm + Turborepo monorepo** 中,并共享一个 `packages/db` 包(Prisma 模式 + 客户端),因此 Next.js 仪表盘和 Skybridge MCP 服务器永远不会重复数据逻辑。
```mermaid
flowchart LR
User((Homeowner)) --> Dash[Next.js dashboard]
User --> LLM[ChatGPT / Claude]
subgraph Monorepo["Monorepo · pnpm + Turborepo"]
Dash --> TRPC[tRPC routers]
LLM --> MCP[MCP tools]
TRPC --> DB["packages/db · Prisma"]
MCP --> DB
end
DB --> PG[(Neon Postgres)]
```
### AI 层
AI 不位于数据库上附加的聊天机器人之上。每个 MCP 工具都是一个小型、特定用途的函数,它提取结构化的家庭数据,运行领域逻辑(账单分解、最佳窗口搜索、能源流动快照),并返回 **两者** 结构化结果和交互式 React 视图。这样可以使模型 **接地**:它根据实际计算的数字回答问题,而不是猜测,用户可以在解释旁边看到底层视图。所有工具都是只读的,因此模型可以自由探索而不会产生副作用。
## MCP 工具
每个工具都呈现一个交互式 React 视图,以及一个结构化的结果。
| 工具 | 视图 | 描述 |
| --- | --- | --- |
| **daily-energy-flow** | 每日能源流动 | 家庭在一天中的实时能源流动快照:太阳能分为自用、电池充电和出口,以及电网进口、电池放电和 SoC。 |
| **explain-bill** | 账单驱动因素分解 | 将两个月份之间的欧元差异分解为驱动因素(能源成本、馈入积分、基本费用),并按区域(房屋、热泵、电动汽车)绘制消费图表。 |
| **best-time-to-run** | 推荐窗口 | 今天/明天运行灵活负载(电动汽车、洗衣机、洗碗机、热泵)的最佳窗口 - 动态关税下的最低成本,固定关税下的最大光伏自用。 |
所有工具都是只读的(`readOnlyHint: true`,`openWorldHint: false`)。
## 数据
四个家庭(Familie Becker、Familie Schmidt、Familie Yilmaz、WG Sonnenallee)的综合全年 2025 数据集,以 15 分钟的分辨率,通过 Prisma 支持 Postgres:
- **家庭、关税和合同** — 资产(光伏、电池、热泵、电动汽车)、动态和标准关税、完整的合同条款。
- **能源记录** — 光伏、房屋负荷、热泵、电动汽车、电池 SoC、电网进口/出口和每 15 分钟的电价(约 140k 行)。
- **动态价格** — 每年的每小时现货价格。
- **每月账单和洞察事件** — 预计算的账单、自给自足率和检测到的异常/提示。
## 技术栈
- **Monorepo:** pnpm 工作区 + Turborepo
- **Web:** Next.js 16、tRPC、React Query、Tailwind、shadcn/ui
- **MCP:** Skybridge(Vite + React 视图)、`@modelcontextprotocol/sdk`
- **数据:** Prisma 7,带有 `@prisma/adapter-pg` 驱动适配器,Neon Postgres
- **托管:** Web 和 MCP 在 Vercel 上,支持 Neon Postgres
## 项目结构
```
├── apps/
│ ├── web/ # Next.js 仪表盘(tRPC + React Query)
│ │ └── src/
│ │ ├── app/ # 应用路由器页面 + API 路由
│ │ └── server/ # tRPC 路由器(家庭、能源、账单、价格、洞察)
│ └── mcp/ # Skybridge MCP 服务器
│ └── src/
│ ├── server.ts # 工具 + 视图定义
│ ├── db.ts # Prisma 客户端访问
│ └── views/ # 每个工具的 React 视图
├── packages/
│ └── db/ # 共享 Prisma 模式、客户端和种子
├── turbo.json
└── pnpm-workspace.yaml
```
## 入门指南
### 先决条件
- Node.js 24+
- pnpm 11+
- Postgres 数据库(本地通过 `docker-compose.yml` 或托管)
### 安装
```bash
pnpm install
```
### 配置
复制示例环境变量并设置您的数据库 URL:
```bash
cp .env.example .env
# DATABASE_URL="postgresql://enpal:enpal@localhost:5439/enpal_track?schema=public"
```
### 设置数据库
```bash
docker compose up -d # 可选:本地 Postgres
pnpm db:push # 应用模式
pnpm db:seed # 加载 2025 数据集
```
### 运行
```bash
pnpm dev
```
这将通过 Turborepo 启动两个应用程序:
- **Web 仪表盘**,位于 `http://localhost:3000`
- **MCP 服务器**,位于 `http://localhost:3001/mcp`(Skybridge DevTools 位于 `http://localhost:3001`)
## 脚本
| 命令 | 描述 |
| --- | --- |
| `pnpm dev` | 在开发模式下运行 web + MCP |
| `pnpm build` | 构建所有应用程序和包 |
| `pnpm lint` | 校验所有包 |
| `pnpm typecheck` | 类型检查所有包 |
| `pnpm db:generate` | 生成 Prisma 客户端 |
| `pnpm db:push` | 将 Prisma 模式推送到数据库 |
| `pnpm db:seed` | 用 2025 数据集播种数据库 |
| `pnpm db:studio` | 打开 Prisma Studio |
## 部署
两个应用程序共享一个 **Neon Postgres** 数据库:
- **Web** (`apps/web`) — 标准的 Next.js 构建,位于 **Vercel** 上。
- **MCP** (`apps/mcp`) — `skybridge build`,部署到 **Vercel** 上。
## 资源
- [Skybridge 文档](https://docs.skybridge.tech/)
- [Apps SDK 文档](https://developers.openai.com/apps-sdk)
- [模型上下文协议文档](https://modelcontextprotocol.io/)