Mortar — 分析与监控(Analytics & Monitoring)
Status:
warehouseprimitive +analytics/monitor事件摄入与 summary 已实装,并在 staging 端到端验证(2026-07-14:POST events → ClickHouse → GET summary →warehouse计量入账、命中免费额度)。**物化视图 rollup(读侧预聚合, 兑现 80% 毛利)+ 跨请求 Buffer(写侧批处理)均已实装并 e2e 验证。**实现以internal/primitive/warehouse/
给用户构建的 app 提供监控(Monitor)和增长 / 产品分析(Grow),
在 Mortar 里不是两个独立产品,而是两个新 capability 模块
(mortar.monitor + mortar.analytics),跑在同一条 per-tenant 事件平面上。
一句话定位:Monitor / Grow / Meter 是同一条事件流的三个视图。 Meter (计费)已经是 Mortar 现有能力(pricing.md);这份文档补的是另外两个。
为什么整进 Mortar,而不是做独立产品
-
Mortar 本来就是那条 per-tenant 平面。 它已经有租户 / workspace 模型、 计量、计费、AppUser 身份(
auth)、4 语言 SDK、以及mortar.*capability-module 模式。Monitor / Grow 就是 per-tenant 事件管道 —— 它们本来就长在这个形状上,自然做法是再加两个模块并排。 -
一个 SDK、一个租户、一个账单 = Firebase 模型。 app 已经 import Mortar SDK、 已经有一个 tenant、已经在 Mortar 出账。
mortar.track(...)直接复用mortar.auth的 AppUser 身份做identify。这正是 Firebase (auth + firestore + analytics + crashlytics 一套 SDK)赢开发者的原因。 -
这让 Mortar 越过 Supabase 的最大缺口。 Supabase 只有基础设施级可观测性 (Logflare 日志 + Postgres 指标),没有产品分析——整个第三方生态就是来补它的。 Mortar 原生带 Monitor + Grow → 相当于「Supabase + PostHog + Sentry 三合一」, 作为独立可售 BaaS 更完整,作为 Fabric 后端也更完整。
primitive vs feature — 唯一的判据
Mortar 的两层结构(见 architecture.md):primitive 是成本维度 (1:1 对应一条云账单行),feature 是组合在 primitive 之上的用户能力。
加 Monitor / Grow 时,判断「什么该是新 primitive」只有一条判据:
这东西有没有产生一条现有 primitive 覆盖不了的新云账单行? 有 → primitive。能用现成的 primitive 拼出来 → feature。
过一遍:
| 东西 | 靠什么云资源 | 判定 |
|---|---|---|
| 事件聚合(漏斗 / 留存 / DAU-MAU / 高基数扫描) | OSS 查不了、Postgres(database)在百万租户尺度跑不动列式聚合 → 必须上 ClickHouse | 新 primitive |
| replay 录制存储 | OSS blob | 现成 storage → feature |
| replay 回放带宽 | egress + OSS GET(GET 本就被吸收) | 现成 network → feature |
| 事件摄入带宽 | ingress(通常不计费) | 现成 network → feature |
| 告警(monitor 发邮件 / 短信) | 阿里云 DM / 短信 | 现成 comms → feature |
结论:唯一的新 primitive 是 OLAP 引擎;monitor / analytics / replay 全是 feature。
唯一新 primitive:warehouse(OLAP 引擎,ClickHouse)
Mortar 从「纯 Postgres OLTP」变为 OLTP + ClickHouse OLAP 双引擎。这是整合的真实代价。
| 引擎 | 装什么 | |
|---|---|---|
| OLTP(现有核心) | Postgres | auth · data(JSONB)· files 元数据 · realtime 状态 · 计量账本 |
| OLAP(唯一新增) | ClickHouse | 事件聚合 — monitor(error / latency)+ analytics(track / 漏斗 / 留存) |
- 列存做高基数聚合,不是复用
data的 Postgres JSONB。 - 独立的高吞吐 ingest 路(写重、append-only、可采样*),不走
auth/data那条同步 GORM/Postgres 请求路:ingest 端点 → buffer → ClickHouse。 - *除 Meter 外可采样 —— 计费事件不能丢、不能采样,永远服务端生成。
- replay 录制 → OSS blob(现有
storage),既不进 Postgres 也不进 ClickHouse。
至此 Mortar 的 primitive 从 7 → 8(compute / database / cache /
storage / network / function / comms / warehouse)。
三个 feature
monitor — 可观测性
错误 / 崩溃 / 延迟 / 健康。事件在 OLAP 引擎里聚合(错误分组、错误率、p95);
告警走现有 comms。是生产可观测性,区别于 harness 里 dev-time 的「AI 修一下」。
analytics — 产品分析(Grow)
track() / identify() / 漏斗 / 留存 / cohort。身份用 mortar.auth 的 AppUser
拼接会话与用户。事件在 OLAP 引擎里聚合。
replay — 会话回放
把用户这次会话实际看到 / 做的一切(DOM 变化、点击、滚动、报错)序列化回放。 Monitor 和 Grow 都用它:看用户怎么撞上 bug、在漏斗哪步跳走。
replay 单拆的原因:一次录制是一个普通事件的成百上千倍字节量。按「1 replay
= 1 event」的扁平单价收会亏穿,所以 Sentry / PostHog 都把它单独按「每次录制」计价。
落地时它是 feature(storage + network 组装),采样录制 + 只给付费档。
客户端采集 — 归属拆两层
后端 / 存储 / 查询 / 计费在 Mortar。客户端采集故意不整块做成一个 Keel module, 按「是否需要原生代码」拆两层:
-
核心捕获 = Mortar SDK(
@mortar-ai/client),框架无关(已实装)。mortar.analytics.track()/.identify()/.captureError()就是普通 JS, 在sdk/typescript/src/analytics.ts:客户端批处理(默认 20 条 / 10s / 页面隐藏 三触发)→POST /v1/{tenant}/analytics/events。因为 app 已经import了 Mortar SDK、已经有一个 tenant、已经在 Mortar 出账,track()零新依赖直接复用 (Firebase 模型)。匿名distinct_id持久化在localStorage/AsyncStorage;identify()复用mortar.auth的 AppUser 身份。浏览器 + RN-JS 通用。 -
原生崩溃捕获 = Mortar 自有的 Keel module(opt-in,待做)。 仅「未捕获的原生崩溃 / ANR / 启动栈」这类必须原生代码的信号,才做成一个 Mortar 拥有的 Keel 原生模块(
create-keel-module,scope 是@mortar-ai/*而非@keel-ai/*),按需装。它同样上报到上面的 ingest 端点。
这是 Mortar 相对 Lovable 的结构性优势:Lovable 生成代码后运行时是别人的、后端是 Supabase,只能「教用户接第三方 SDK,数据进用户自己账号」;Mortar 能把采集烤进 自家 SDK,数据流进自家事件面 —— 一个 SDK、一个租户、一个账单。
API(已实装)
两个 tenant-scoped 端点,app/admin key 鉴权(Mortar SDK 客户端用 app key)。
摄入 — POST /v1/{tenant}/analytics/events
{ "events": [
{ "kind": "analytics", "name": "pageview", "distinct_id": "u1", "session_id": "s1", "props": {} },
{ "kind": "monitor", "name": "error" }
]}
→ 202 { "accepted": 2 }
kind = analytics | monitor(默认 analytics);批量上限 500/请求;name 必填;
timestamp 缺省用服务端时间;每事件计一条 warehouse 用量。
读取 — GET /v1/{tenant}/analytics/summary?from=&to=(RFC3339;默认最近 7 天,90 天封顶)
{ "from": "...", "to": "...",
"total_events": 4, "unique_visitors": 2, "sessions": 2,
"by_name": { "pageview": 2, "signup": 1, "error": 1 },
"series": [ { "date": "2026-07-14", "events": 4 } ] }
unique_visitors/sessions 走 ClickHouse uniqExactIf;series 是趋势图的按日计数。
未配 ClickHouse(MORTAR_CLICKHOUSE_URL 空)→ 两个端点 503 analytics_not_configured。
计费 — 复用现有计量,不建新引擎
Mortar 现有两轴:plan(Free / Pro / Team / Enterprise 订阅)× tier (Nano…Large 容量,见 pricing.md)。Monitor / Grow 不新建计费引擎, 其用量并入现有计量。
- primitive(原始云成本):
warehouse= ClickHouse compute + storage,新云账单行。 - 对用户计费单位(feature 层):
per-event/per-error← 背后是warehouseper-replay← 背后是storage+networkretention= 套餐 / tier 属性(不做计量维度,直接封顶存储 COGS)
关键区分:
event(事件量)是对用户的计费单位,不是 primitive; primitive 是那条新的 ClickHouse 云账单行。这与 Mortar 现状一致 —— 定价本就 对齐模型成本、能捆则捆(3 个 baseline 维度合成一个 tier 基线、OSS API 请求 被吸收),并非严格 1:1;event(+replay单拆)完全套这个模板。
Meter 是 Monitor / Grow 付费档的收费引擎:用户越自定义、埋越多事件、开 replay / 深分析 → 用量越大 → 账单越高。也就是说,「Grow 可自定义」本身就是收费曲线。
边界:Fabric 自有可观测性不在这条平面上
这条事件平面服务的是「用户构建的 app」(Mortar 租户)。 Fabric 自己的平台服务 (fabric-server / harness / mortar-cloud / keel-cloud)用的是独立的一套 (Sentry / OpenTelemetry),不走 Mortar —— Fabric 不跑在 Mortar 上,它保留 自己的账户与可观测栈。别把「给租户 app 的 Monitor/Grow」和「Fabric 平台自监控」混。
OpenTelemetry 的位置:它是运营 / 跨服务 trace 的正确标准(服务端 Mortar 埋点 + 以后端到端 trace),不是产品分析(Grow)的模型 —— 后者要「命名事件 + 任意属性
- 用户身份」的 schema,OTLP span 给不了。客户端主力是薄的自建
track()/ crash SDK,OTel 用在服务端。
分阶段 roadmap
按「杠杆最大、成本最低」排序,和市场验证一致(Lovable 唯一自建的就是阶段一那块)。
- 零配置流量基线(Grow 的 80/20) — published app 的零配置实时 analytics
dashboard(访客 / PV / 来源 / 设备),ClickHouse 底座。非技术用户真正想要的
「有没有人来用我的 app」。参照:Lovable 同款约 1 人 · 1 周。
✅ 后端已实装(ingest + summary + trend series on ClickHouse,staging e2e 通过);
✅ Fabric Cloud dashboard tab 已铺(五端:web / iOS / Android / desktop / wechat,
经 fabric-server 代理读 summary);✅ 客户端采集 SDK 核心已实装
(
mortar.analytics.track/identify/captureErrorin@mortar-ai/client,批处理 + flush)。 剩:发布@mortar-ai/client新版 + 让 Fabric 的 skill/prompt 教 AI 调mortar.analytics.*。 - 错误监控(Monitor) — JS 未捕获错误已可
captureError()上报;剩原生 crash / ANR (Mortar 自有 Keel module)+ 分组 dashboard。全品类公开缺口(连 Lovable 都靠 AI 「Try to Fix」糊),先做者有卖点。 - 深度产品分析(付费档) —
track()/identify()+ 漏斗 / 留存 / cohort;replay(采样、付费)。 - 计费接入 — 各阶段用量并入 Mortar 计量(
per-event/per-replay/retention封顶),warehouseprimitive 上线。
与竞品
| 玩家 | 给用户 app 的 Monitor + Grow |
|---|---|
| Supabase | 只有基础设施级(Logflare 日志 + Postgres 指标),无产品分析、无 uptime |
| Lovable | 薄自建:一块零配置流量 dashboard(ClickHouse 底座),深度全甩第三方(教用户接 PostHog / GA) |
| Firebase | 全家桶自建(Crashlytics + GA for Firebase + Performance Monitoring) |
| Mortar(本设计) | 一体化自建:monitor + analytics + replay 作为 capability,一个 SDK,计费复用现有计量;靠拥有 Keel 运行时 + Mortar 后端做到 Lovable 给不了的采集一体化 |
See also
- analytics-release-checklist.md — 上线 checklist(发布 / skill sha / 部署)
- architecture.md — 7 → 8 primitive × feature 结构
- pricing.md — plan × tier 两轴 + 计量
internal/plan/registry.go— 定价 / primitive 权威源