Mortar — 分析与监控(Analytics & Monitoring)

Status: warehouse primitive + 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,而不是做独立产品

  1. Mortar 本来就是那条 per-tenant 平面。 它已经有租户 / workspace 模型、 计量、计费、AppUser 身份(auth)、4 语言 SDK、以及 mortar.* capability-module 模式。Monitor / Grow 就是 per-tenant 事件管道 —— 它们本来就长在这个形状上,自然做法是再加两个模块并排。

  2. 一个 SDK、一个租户、一个账单 = Firebase 模型。 app 已经 import Mortar SDK、 已经有一个 tenant、已经在 Mortar 出账。mortar.track(...) 直接复用 mortar.auth 的 AppUser 身份做 identify。这正是 Firebase (auth + firestore + analytics + crashlytics 一套 SDK)赢开发者的原因。

  3. 这让 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(现有核心)Postgresauth · 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, 按「是否需要原生代码」拆两层:

  1. 核心捕获 = 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 通用。

  2. 原生崩溃捕获 = 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 ← 背后是 warehouse
    • per-replay ← 背后是 storage + network
    • retention = 套餐 / 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 唯一自建的就是阶段一那块)。

  1. 零配置流量基线(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/captureError in @mortar-ai/client,批处理 + flush)。 剩:发布 @mortar-ai/client 新版 + 让 Fabric 的 skill/prompt 教 AI 调 mortar.analytics.*
  2. 错误监控(Monitor) — JS 未捕获错误已可 captureError() 上报;剩原生 crash / ANR (Mortar 自有 Keel module)+ 分组 dashboard。全品类公开缺口(连 Lovable 都靠 AI 「Try to Fix」糊),先做者有卖点。
  3. 深度产品分析(付费档)track() / identify() + 漏斗 / 留存 / cohort; replay(采样、付费)。
  4. 计费接入 — 各阶段用量并入 Mortar 计量(per-event / per-replay / retention 封顶),warehouse primitive 上线。

与竞品

玩家给用户 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