如何构建像EnergySage一样的太阳能安装工目录
像 EnergySage 一样构建太阳能安装商目录
如果你曾经搜索过"find solar installer near me",你可能会登陆 EnergySage。它是美国主导的太阳能市场,连接房主与经过审查的安装商,生成有竞争力的报价,并每周拉取数百万个数据点。美国能源部直接资助了它的开发。如果你正在读这篇文章,你可能想构建类似的东西。
在过去的几年里,我为能源、家庭服务和B2B垂直领域的客户构建过目录式市场和基于地理位置的服务平台。太阳能安装商目录背后的架构并不是火箭科学,但有许多决定可以决定项目的成败。让我为你详细讲解整个过程——从数据建模到搜索基础设施再到真正驱动有机流量的SEO策略。
目录
理解太阳能市场模式
在写一行代码之前,你需要理解像 EnergySage 和 solar.com 这样的平台作为商业运作的原理。它们是具有特定收入模式的双边市场:
- 房主输入他们的地址和电力信息来请求太阳能报价
- 安装商付费访问这些线索并按价格和质量竞争
- 平台通过安装商订阅、按线索收费或分享已成交交易获得收入
EnergySage 报告说他们的市场为房主节省了大约每瓦 $0.20–$0.40 比直接联系安装商——典型的 5 kW 住宅系统上是 $1,000–$2,000。这种节省来自竞争。当多个安装商竞争同一个项目时,价格会下降。这是你需要复制的核心价值主张。
2025年太阳能市场仅在美国就是一个价值 $30+ 亿的产业,住宅安装以每年约 15-20% 的速度增长。《通货膨胀削减法》的 30% 联邦税收抵免一直运行到 2032 年,所以这个市场不会放缓。
以下是主要参与者的样子:
| 平台 | 模式 | 收入来源 | 安装商网络 |
|---|---|---|---|
| EnergySage | 报价市场 | 线索费 + 数据许可 | 500+ 经过审查的安装商 |
| Solar.com | 引导市场 | 优惠定价佣金 | 策划的网络 |
| Enphase 安装商定位器 | 设备绑定目录 | 硬件销售 | 认证的 Enphase 安装商 |
| SolarReviews | 评论目录 | 线索生成费 | 500+ 上市公司 |
| Yelp/Google | 普通目录 | 广告 | 未审查的上市 |
你的目录不需要与 EnergySage 直接竞争。利基机会存在:州特定目录、仅限商业的市场、电池存储专家或专注于特定设备品牌的目录。
核心架构决策
第一个真正的决定是你是在构建静态目录、动态市场还是介于两者之间的东西。每种都有完全不同的复杂性。
静态目录 vs. 动态市场
静态目录列出安装商的联系信息、评论和服务区域。可以想象是太阳能的黄页。复杂性低,快速构建,通过广告或特色列表变现。
动态市场处理整个报价到成交的工作流:线索捕获、安装商匹配、报价生成、比较工具,有时甚至融资。这就是 EnergySage 做的。复杂性高,但收入潜力更高。
大多数团队应该从目录开始,然后在上面分层市场功能。原因是:目录页面产生有机流量(想想成千上万个"[城市] 的太阳能安装商"页面),该流量为市场漏斗提供支持。
无头架构
对于这样的项目,我强烈推荐无头架构。以下是我会使用的设置:
- 前端:Next.js 或 Astro 用于面向公众的网站
- CMS:无头 CMS(Sanity、Contentful 或 Payload)用于安装商档案和编辑内容
- API 层:自定义 Node.js/Express 或 tRPC API 用于搜索、报价和交易逻辑
- 数据库:PostgreSQL 加 PostGIS 用于地理空间查询
- 搜索:Algolia 或 Meilisearch 用于即时安装商搜索
我们为客户使用我们的 Next.js 开发 和 无头 CMS 能力构建了类似的架构。无头方法让你独立地扩展内容层(数千个位置页面)与应用层(报价引擎、用户仪表板)。
单体仓库结构
我会使用 Turborepo 将其组织为单体仓库:
├── apps/
│ ├── web/ # Next.js 公开网站
│ ├── installer-portal/ # 安装商仪表板 (Next.js)
│ └── admin/ # 内部管理员 (React)
├── packages/
│ ├── database/ # Prisma 模式 + 迁移
│ ├── api/ # 共享 API 路由/tRPC
│ ├── ui/ # 共享组件库
│ └── geo/ # 地理空间实用程序
└── turbo.json
随着项目增长,这可以保持组织整洁。geo 包值得特别提及——你将在多个应用中重用地理空间逻辑(距离计算、服务区匹配、地理编码)。
安装商目录的数据库设计
这是大多数目录项目要么成功要么创建多年来困扰的地方。让我分享一个行之有效的模式。
核心实体
-- 安装商公司
CREATE TABLE installers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) UNIQUE NOT NULL,
description TEXT,
website_url VARCHAR(500),
phone VARCHAR(20),
email VARCHAR(255),
logo_url VARCHAR(500),
founded_year INTEGER,
employee_count_range VARCHAR(50),
license_number VARCHAR(100),
is_verified BOOLEAN DEFAULT FALSE,
verification_date TIMESTAMP,
avg_rating DECIMAL(2,1) DEFAULT 0,
total_reviews INTEGER DEFAULT 0,
total_installations INTEGER DEFAULT 0,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 服务区域(使用 PostGIS 用于地理查询)
CREATE TABLE service_areas (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
installer_id UUID REFERENCES installers(id),
area_name VARCHAR(255),
geometry GEOMETRY(POLYGON, 4326),
radius_miles INTEGER,
center_point GEOMETRY(POINT, 4326),
is_primary BOOLEAN DEFAULT FALSE
);
-- 认证和证书
CREATE TABLE installer_certifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
installer_id UUID REFERENCES installers(id),
certification_type VARCHAR(100), -- 'NABCEP', 'Tesla Powerwall', 'Enphase', 等等
certification_number VARCHAR(100),
issued_date DATE,
expiry_date DATE,
verified BOOLEAN DEFAULT FALSE
);
-- 他们安装的设备/品牌
CREATE TABLE installer_equipment (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
installer_id UUID REFERENCES installers(id),
equipment_type VARCHAR(50), -- 'panel', 'inverter', 'battery'
brand VARCHAR(100),
model VARCHAR(255),
is_preferred BOOLEAN DEFAULT FALSE
);
-- 位置页面 (用于 SEO)
CREATE TABLE locations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
state VARCHAR(2) NOT NULL,
city VARCHAR(255) NOT NULL,
county VARCHAR(255),
slug VARCHAR(255) UNIQUE NOT NULL,
zip_codes TEXT[], -- 覆盖的邮编数组
center_point GEOMETRY(POINT, 4326),
avg_system_cost DECIMAL(10,2),
avg_electricity_rate DECIMAL(5,4),
avg_sun_hours DECIMAL(4,2),
state_incentives JSONB,
installer_count INTEGER DEFAULT 0,
meta_title VARCHAR(70),
meta_description VARCHAR(160),
content TEXT, -- Markdown 编辑内容
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
服务区问题
这是棘手的部分。安装商不提供围绕单个点的整洁的圆形区域。他们提供奇形怪状的区域——可能是一个州的三个县,加上另一边的几个邮编。你有三个选择:
- 基于半径:安装商设置中心点和最大距离。简单但不准确。
- 邮编列表:安装商选择特定邮编。准确但对于大面积来说繁琐。
- 基于多边形:在地图上绘制实际的服务区边界。最准确,最好的用户体验,但需要 PostGIS 和地图绘制用户界面。
我会用选项 1 作为后备实现选项 3。在入职期间,让安装商要么在 Mapbox/Google Maps 界面上绘制他们的服务区域,要么只输入一个半径。使用 PostGIS 的 ST_Contains 和 ST_DWithin 函数进行匹配:
-- 查找为特定点(房主地址)提供服务的安装商
SELECT i.* FROM installers i
JOIN service_areas sa ON sa.installer_id = i.id
WHERE ST_Contains(sa.geometry, ST_SetSRID(ST_MakePoint(-71.4128, 41.8240), 4326))
AND i.status = 'active'
ORDER BY i.avg_rating DESC;
基于地理位置的搜索和位置服务
"find solar installer near me" 查询就是一切。它是主要用户意图、主要 SEO 目标和核心用户体验流。你需要正确处理这个。
地理编码管道
当房主输入他们的地址或邮编时,这是流程:
- 客户端:使用 Google Places API 或 Mapbox Geocoding 的自动完成
- 地理编码:将地址转换为经纬度坐标
- 查询:查找服务区包含该点的安装商
- 丰富:拉入本地电力公司数据、州激励、平均太阳辐照度
- 排名:按相关性排序(评级、距离、响应时间、验证状态)
// 示例:安装商搜索的 Next.js API 路由
import { db } from '@/packages/database';
import { geocode } from '@/packages/geo';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const zipCode = searchParams.get('zip');
const lat = searchParams.get('lat');
const lng = searchParams.get('lng');
let coordinates = { lat: Number(lat), lng: Number(lng) };
if (zipCode && (!lat || !lng)) {
coordinates = await geocode(zipCode);
}
const installers = await db.$queryRaw`
SELECT
i.*,
ST_Distance(
sa.center_point::geography,
ST_SetSRID(ST_MakePoint(${coordinates.lng}, ${coordinates.lat}), 4326)::geography
) / 1609.34 as distance_miles
FROM installers i
JOIN service_areas sa ON sa.installer_id = i.id
WHERE (
ST_Contains(sa.geometry, ST_SetSRID(ST_MakePoint(${coordinates.lng}, ${coordinates.lat}), 4326))
OR ST_DWithin(
sa.center_point::geography,
ST_SetSRID(ST_MakePoint(${coordinates.lng}, ${coordinates.lat}), 4326)::geography,
sa.radius_miles * 1609.34
)
)
AND i.status = 'active'
ORDER BY i.is_verified DESC, i.avg_rating DESC, distance_miles ASC
LIMIT 20
`;
return Response.json({ installers, coordinates });
}
搜索基础设施
对于即时搜索(按名称、认证、设备品牌过滤),一旦你超过几千个安装商,PostgreSQL 单独会变得缓慢。在上面分层 Algolia 或 Meilisearch:
| 功能 | Algolia | Meilisearch | PostgreSQL 全文搜索 |
|---|---|---|---|
| 延迟 | <50ms | <50ms | 100-500ms |
| 地理过滤 | 内置 | 内置 | 需要 PostGIS |
| 分面搜索 | 优秀 | 良好 | 手动 |
| 容错 | 是 | 是 | 否 |
| 定价 (2025) | $1/1K 请求 | 免费 (自托管) | 免费 |
| 设置复杂性 | 低 | 中等 | 低 |
Algolia 在每 1,000 个搜索请求 $1 对大多数目录来说是合理的。如果预算紧张,在 $20/月 VPS 上自托管 Meilisearch。
构建报价请求系统
这是将目录与市场区分开来的东西。报价系统是你的收入引擎。
报价请求流程
- 房主输入地址 → 自动检测电力公司和费率
- 屋顶评估(来自 Google Solar API 或 Aurora Solar 的卫星图像)
- 基于使用情况和屋顶空间的系统大小推荐
- 与该区域 3-8 个合格安装商进行匹配
- 安装商在 48 小时内提交竞争性报价
- 房主在标准化仪表板上比较报价
Google Solar API(2023 年推出,现在广泛可用)是这里的一个巨大捷径。它为美国 320+ 百万栋建筑提供太阳能潜力数据,包括:
- 屋顶分段分析
- 年日照小时数
- 估计能量产生
- 最优面板放置
// Google Solar API - 建筑见解
const response = await fetch(
`https://solar.googleapis.com/v1/buildingInsights:findClosest?` +
`location.latitude=${lat}&location.longitude=${lng}` +
`&requiredQuality=HIGH&key=${GOOGLE_SOLAR_API_KEY}`
);
const data = await response.json();
// data.solarPotential.maxArrayPanelsCount
// data.solarPotential.maxSunshineHoursPerYear
// data.solarPotential.financialAnalyses
这消除了初始报价阶段对手动现场调查的需要,大大减少了报价时间。
报价数据模型
每个报价需要捕获足够的细节以进行有意义的比较:
interface SolarQuote {
id: string;
requestId: string;
installerId: string;
systemSizeKw: number;
panelBrand: string;
panelModel: string;
panelCount: number;
inverterBrand: string;
inverterType: 'string' | 'micro' | 'hybrid';
batteryIncluded: boolean;
batteryBrand?: string;
batteryCapacityKwh?: number;
grossCost: number;
federalTaxCredit: number;
stateIncentives: number;
utilityRebates: number;
netCost: number;
estimatedAnnualProduction: number;
warrantyYears: number;
estimatedPaybackYears: number;
financingOptions: FinancingOption[];
validUntil: Date;
}
本地太阳能页面的SEO架构
这是大多数太阳能目录要么成功要么失败的地方。EnergySage 从程序化位置页面生成大量有机流量——他们有针对每个州每个城市的页面,结构为 /local-data/solar-companies/{state}/{county}/{city}/。
URL 结构
这是我推荐的 URL 层次结构:
/solar-installers/ # 国家中心
/solar-installers/rhode-island/ # 州页面
/solar-installers/rhode-island/providence/ # 城市页面
/installer/blue-sky-solar/ # 个别安装商档案
/solar-costs/rhode-island/ # 按州的成本数据
程序化页面生成
使用 Next.js App Router,你可以在构建时生成成千上万的位置页面:
// app/solar-installers/[state]/[city]/page.tsx
export async function generateStaticParams() {
const locations = await db.location.findMany({
select: { state: true, slug: true }
});
return locations.map((loc) => ({
state: loc.state.toLowerCase().replace(/\s+/g, '-'),
city: loc.slug,
}));
}
export async function generateMetadata({ params }: Props) {
const location = await getLocation(params.state, params.city);
return {
title: `${location.city}, ${location.state} 最佳太阳能安装商 (2025)`,
description: `比较 ${location.city} 的 ${location.installerCount} 家经过审查的太阳能公司。平均系统成本:$${location.avgSystemCost}。立即获取免费报价。`,
};
}
对于有 10,000+ 位置页面的网站,考虑使用 Astro 而不是 Next.js。Astro 的静态生成对于内容丰富的网站显著更快——我们看到对于大型程序化页面集的构建时间从 45 分钟下降到 5 分钟以下。
位置页面的内容策略
不要只生成空白的模板页面。每个位置页面需要独特、有用的内容:
- 该地区的活跃安装商数量
- 该城市的平均太阳能系统成本(从你的报价数据中拉取)
- 本地电力公司费率和净计量政策
- 州和本地激励(这些差异很大)
- 平均太阳辐照度 / 日照小时数
- 顶级评价的安装商,具有真实评论
- 最近报价的比较表格
例如,EnergySage 的普罗维登斯、RI 页面列出了 8 个市场安装商,其中包括关于经验、认证和设备偏好的详细信息。这是你竞争的深度。
安装商验证和信任信号
信任是整个游戏。EnergySage 验证安装商有 2-3 年的经验和多个成功安装,然后他们才能加入。Solar.com 谈到"剔除三流企业"。你需要一个验证管道。
验证清单
- 营业执照:通过 API 验证州承包商执照(许多州有公开查询 API)
- 保险:要求通用责任保险证明($1M+)和工人赔偿
- NABCEP 认证:太阳能安装商的金标准——根据 NABCEP 的数据库进行验证
- 经营年限:与州业务登记交叉参考
- 安装历史:请求已完成项目的投资组合
- 背景检查:对于竞标住宅项目的公司
- 评论:从 Google、Yelp、BBB 和你自己的平台汇总
信任用户界面元素
在安装商档案上突出显示验证状态:
<div className="flex items-center gap-2">
<VerifiedBadge />
<span className="text-sm text-green-700">
已验证:许可证 #12345 • NABCEP 认证 •
投保至 $2M • {yearsInBusiness} 年经验
</span>
</div>
在每个页面上包含"为什么你可以信任我们"部分——EnergySage 这样做并且有效。透明地解释你的审查过程。
技术栈推荐
以下是我在 2025 年实际会用来构建这个的东西:
| 层 | 技术 | 为什么 |
|---|---|---|
| 前端 | Next.js 15 (App Router) | SSR + ISR 用于动态页面,RSC 用于性能 |
| 样式 | Tailwind CSS + shadcn/ui | 快速迭代、可访问的组件 |
| CMS | Payload CMS (自托管) | 开源、适合自定义集合 |
| 数据库 | PostgreSQL 16 + PostGIS | 地理空间查询、可靠性 |
| ORM | Prisma + 原始 SQL 用于地理 | 两全其美 |
| 搜索 | Meilisearch (自托管) | 免费、快速、地理感知 |
| 地图 | Mapbox GL JS | 大规模定价比 Google Maps 更好 |
| 地理编码 | Mapbox Geocoding API | 每 1,000 个请求 $0.75 |
| 托管 | Vercel (前端) + Railway (API + DB) | 轻松部署、合理的定价 |
| 认证 | Clerk 或 NextAuth.js | 房主和安装商的单独流程 |
| 监控 | Sentry + Plausible Analytics | 错误跟踪 + 隐私友好的分析 |
| 电子邮件 | Resend | 报价通知的交易电子邮件 |
处理约 10,000 月度用户的 MVP 的总基础设施成本:大约 $150-300/月。在规模上(100K+ 月度用户),预期 $800-2,000/月,不包括 API 成本。
如果你想正确构建这个,请查看我们的 定价 或 直接联系。我们为类似架构的多千页面目录网站构建过。
性能基准和成本预估
这是现实的开发时间表样子:
| 阶段 | 范围 | 时间表 | 成本范围 |
|---|---|---|---|
| MVP 目录 | 安装商列表、地理搜索、位置页面 | 8-12 周 | $30K-60K |
| 报价系统 | 线索捕获、安装商匹配、报价比较 | 6-8 周 | $25K-45K |
| 安装商门户 | 仪表板、线索管理、分析 | 4-6 周 | $15K-30K |
| 房主仪表板 | 已保存报价、消息、项目跟踪 | 4-6 周 | $15K-25K |
| 支付集成 | 安装商订阅、线索付款 | 2-3 周 | $8K-15K |
| 总计 MVP 市场 | 24-35 周 | $93K-175K |
这些是具有经验丰富的团队的高质量构建的现实数字。我看到机构报价超过 $250K 以获得相似的范围,我看到团队试图以 $15K 完成并最终得到在真实流量下瓦解的东西。
你应该达到的性能目标:
- 位置页面加载:< 1.5s (LCP) -- 这些是你的 SEO 金牌页面
- 搜索结果:从按键到结果 < 200ms
- 地理查询:对于"[邮编] 附近的安装商" < 100ms
- 核心网络生命体征:整个板面全绿
- 构建时间:5,000+ 静态页面 < 10 分钟
常见问题
构建一个像 EnergySage 这样的太阳能安装商目录需要花多少钱? 一个基本的具有地理搜索和安装商档案的目录可以以 $30K-60K 构建。一个具有报价比较、安装商仪表板和支付处理的完整市场通常运行 $93K-175K,具体取决于功能范围。EnergySage 本身由能源部赠款资助,已融资超过 $1000 万风险投资,所以不要指望在紧张预算上复制他们的完整功能集。
我应该为太阳能市场使用什么技术栈? 我推荐 Next.js 15 用于前端(SSR 能力对 SEO 至关重要),PostgreSQL 加 PostGIS 用于地理空间查询,以及 Algolia 或 Meilisearch 用于即时搜索。对于 CMS 层,Payload CMS 或 Sanity 适用于管理安装商档案和编辑内容。在 Vercel 上为前端和 Railway 或 Render 为你的数据库和 API 托管。
像 EnergySage 这样的太阳能市场平台如何赚钱? EnergySage 使用一个线索生成模型,其中安装商付费访问合格房主线索。他们还向投资公司、学术研究人员和政府机构许可他们广泛的太阳能定价数据。Solar.com 采取略有不同的方法,使用优惠定价佣金。大多数目录网站从特色列表费开始(每个安装商每月 $50-500),并在规模上演变成按线索定价(每个合格线索 $20-100)。
我如何获取太阳能安装商数据来填充我的目录? 从爬取公开数据开始:州承包商执照数据库、NABCEP 的认证安装商目录和制造商定位器(如 Enphase 的安装商网络)。然后构建一个入职流程,安装商可以声称和增强他们的档案。早期,你需要手动联系安装商——向他们提供免费列表来为市场播种。冷启动问题是真实的;没有人想加入一个空市场。
SEO 对太阳能安装商目录有多重要? 这本质上是你的整个增长策略。针对"[城市] 的太阳能安装商"查询的程序化位置页面是 EnergySage 驱动其大部分流量的方式。你会希望为每个主要城市和州有独特的页面,每个都具有真实的本地数据(平均成本、激励信息、安装商数量)。没有强劲的有机搜索性能,你会在试图竞争时烧掉付费获取预算。
我应该为地图功能使用 Google Maps 还是 Mapbox? 在大多数情况下是 Mapbox。Google Maps 定价快速变得昂贵——Maps JavaScript API 在每月 $200 的免费信用后对每 1,000 次加载收费 $7。Mapbox 对每 1,000 地图加载收费 $0.60,每月 50,000 次免费加载。对于可能在数千个位置页面上呈现地图的目录,Mapbox 可以每月为你节省数千美元。但是,使用 Google 的 Solar API 来获取建筑见解数据——没有其他东西相近。
我应该如何处理安装商验证和审查? 构建一个多步骤验证管道:检查州承包商执照数据库(许多有公开 API)、验证 NABCEP 认证、要求保险证明并交叉参考业务登记记录。EnergySage 需要 2-3 年的经验和多个已完成的安装。自动化你能做的,但期望进行一些手动审查。突出显示验证徽章——它们直接影响房主转换率。
我可以使用 Google Solar API 来估计太阳能潜力吗? 是的,你应该。Google 的 Solar API 覆盖美国 320+ 百万栋建筑,并提供屋顶分段分析、年日照数据和估计的能量产生。它每 1,000 个请求成本 $10 用于建筑见解。当房主输入他们的地址时使用它来预先填充系统大小估计——这大大改进了报价请求体验并在安装商甚至参与之前设置现实期望。