Portfolio View
📋 需求对照说明书(给产品经理)· Linear AXI-69~72 → 界面功能 → 怎么算的
AXI-69Portfolio View: Aggregation Engine
Linear 原文(逐字):
Period-based aggregation across all active properties in a GP account. For each period, sum revenue and cost items of every property active in that period. Do not normalize holding periods across deals. Build the portfolio timeline from the earliest acquisition date to the latest disposition date across the account. A property not active in a given period contributes zero to that period. Expose per-period aggregate values so downstream metric and period-over-period logic can consume them.
➡️ 对应界面功能:下方「逐行汇总表」(Rollup)—— 所选多个项目按月加总后的收入/成本明细。
🛠️ 我们的实现 / 模糊点备注:已实现:按「日历月」把所选项目每一行收入/成本跨项目相加(DB 侧 GROUP BY),不活跃的月贡献 0,时间轴取所有项目里最早收购~最晚处置。模糊点:原文说 “a GP account”,但我们没有“GP 账户”这个东西,见下方「GP 与账号关系」。
⚠️ 看上去清楚、落地才发现没说清的点:
  • “a GP account” 到底指什么?系统里没有“GP 账户”。我们改成“用户选中的一组项目”。
  • “revenue and cost items” 具体是哪些行?我们定为:租金收入各行 + 其他收入 + 运营费用(含税/保险) + NOI,纯 $ 可加项;比率/IRR/人均等不加。
  • “active in that period” 用哪个日期判活跃?我们用 tb_deal 的收购日~处置日窗口。
  • “period” 是日历月还是各 deal 的持有期序号?各 deal 起止不一,我们统一按日历月对齐(原文说不要归一化持有期)。
AXI-70Portfolio View: Metric Calculations
Linear 原文(逐字):
The four v1 operating metrics, each computed per period off the aggregation engine's output. NOI = Sum across active properties in period. Revenue = Sum across active properties in period. Operating Expenses = Sum across active properties in period. Occupancy = Total occupied SF ÷ total leasable SF across active properties. Occupancy note: Weight by leasable SF. Sum occupied SF and leasable SF across active properties, then divide. Do not average per-property occupancy rates.
➡️ 对应界面功能:「Metrics」区 —— NOI / Revenue / Operating Expenses / Occupancy(逐月、可切 S0/S1/S2、可切图表)。
🛠️ 我们的实现 / 模糊点备注:NOI/Revenue/OpEx 就是逐月跨项目求和,直接投影。Occupancy 原文写的是 “occupied SF ÷ leasable SF”,但那是 rent-roll 快照(一个时间点),而 Portfolio 是预测(逐月该变化),快照平铺到每期是错的。所以改成从预测租金派生逐月占用率;又因“到底算哪种”没说清,我们算了两种(物理/经济),rent-roll 快照单独保留。见下方口径表。
⚠️ 看上去清楚、落地才发现没说清的点:
  • Occupancy 的分子/分母没定义清楚:是 rent-roll 快照 SF(历史一个点)还是逐月预测?这是两个完全不同的东西。
  • 就算按“occupied SF ÷ leasable SF”,预测期根本没有逐月的 occupied SF 序列(rent-roll 只有一个快照),字面照做会让每个预测月都是同一个数。
  • 要不要把让利(concession)、低租(loss-to-lease)算进“没收满”?物理口径不算、经济口径算 —— 原文没说,我们两种都给。
  • NOI/Revenue/OpEx 用哪个场景?含不含 CapEx?我们暴露 S0/S1/S2 让你切(S0 含 CapEx / S1 不含)。
  • “per period” 含不含持有期之外的 forward 月?我们只取持有期内(out_of_holding_period=0)。
指标分子分母数据来源业务逻辑(大白话)
NOI(净营业收入)
金额
所选各物业当月 NOI 逐一相加—(纯求和,无分母)预测报表的 NOI 序列(noi 源 / NET_OPERATING_INCOME)把所有选中项目当月的净营业收入直接加起来。不活跃的项目当月算 0。
Revenue(营业收入)
金额
各物业当月「租金收入各行」+「其他收入」相加—(纯求和,无分母)rent 源(RENTAL_INCOME)+ other_income 源(OTHER_INCOME)所有选中项目当月的收入合计(含租金与其他收入)。
Operating Expenses(运营支出)
金额
各物业当月运营费用相加(含物业税、保险)—(纯求和,无分母)expense 源(EXPENSE / PROPERTY_TAXES / INSURANCE)所有选中项目当月的运营支出合计。
Occupancy · 物理口径(预测·逐月·逐场景)
百分比
潜在租金 − 空置损失(= 扣掉空置后的租金)潜在租金(Market Rent / GPR)预测租金 tb_report_rent_item,跨物业先求和再相除;随 S0/S1/S2 逐月变化反映“楼有多满”。= 1 − 空置损失 ÷ 潜在租金。只扣纯空置,不含让利/低租。多物业按潜在租金加权(先加金额、再相除,不是把各物业占用率求平均)。
Occupancy · 经济口径(预测·逐月·逐场景)
百分比
潜在租金 − 空置 − 低租(Loss-to-Lease) − 让利(Concessions)潜在租金(Market Rent / GPR)预测租金 tb_report_rent_item,跨物业先求和再相除;随 S0/S1/S2 逐月变化反映“实际收到的有效租金占潜在租金的比例”。= 1 − (空置+低租+让利) ÷ 潜在租金。比物理口径更低,因为把让利和低租也算作“没收满”。
Occupancy · Rent-Roll 初期快照(非预测,单值)
百分比
已占用单元的 SF(占用状态单元面积之和)可租 SF(rent-roll 全部单元面积之和)rent-roll 上传快照,多物业叠加;只有一个时间点的值这才是 Linear 原文说的“occupied SF ÷ leasable SF”。但 rent-roll 是一个时间点的快照,只能当“初期占用率”单独看一眼,不能摊到每个预测月(否则每个预测月都会是同一个数)。
AXI-71Portfolio View: Context Strip
Linear 原文(逐字):
A persistent strip displayed alongside the metrics at all times, showing, for the selected period: Active property count; Active units and leasable SF; Properties acquired or sold during the period, if any. Why it's mandatory: without it, a jump in NOI can't be distinguished between real performance improvement and simply more properties entering the active set. The strip must remain visible for every period.
➡️ 对应界面功能:顶部「Context」常驻带 —— 活跃物业数 / 活跃单元 / 可租 SF + 当期收购/处置。
🛠️ 我们的实现 / 模糊点备注:已实现,常驻显示(无需切换)。活跃/收购/处置口径来自 tb_deal 的收购~处置窗口。作用:NOI 涨了,先看这条带 —— 是真的经营变好,还是只是多了几个物业进来。
⚠️ 看上去清楚、落地才发现没说清的点:
  • “Active units”从哪来、怎么定义?是 rent-roll 的单元条数,还是 unit config 的配置数?我们用当前 rent-roll 的单元数。
  • “leasable SF”同样是 rent-roll 快照口径 —— 和 Occupancy 一样存在“快照 vs 逐月”的问题。
  • “acquired or sold during the period”里的“during”按哪个日期?我们用 tb_deal 的收购/处置日落在该月即算。
  • 同一个月多个物业进/出怎么呈现?原文没说,我们把名字都列出来。
AXI-72Portfolio View: GP-view Routing and Access
Linear 原文(逐字):
Make the portfolio view reachable and access-controlled for GP-role users. Route a logged-in GP-role user to the Portfolio View. Scope the view to GP role for v1. No LP view in this release. Acceptance: a logged-in GP-role user can reach the Portfolio View; the view renders the metrics and context strip for that account's active properties.
➡️ 对应界面功能:侧栏「Portfolio View」入口 + 访问范围(谁能看到哪些项目)。
🛠️ 我们的实现 / 模糊点备注:原文假设有一种“GP-role user”(账户级角色),但我们系统里没有这个属性 —— GP/LP 是「逐项目的资本结构」(某公司在这个项目当 GP、在另一个项目当 LP),不是一个人固定的身份。所以我们没按“GP 角色”做门,改成:你能看到的项目 = 你在「Projects 列表」里本就能看到的。详见下方「GP 与账号关系」。
⚠️ 看上去清楚、落地才发现没说清的点:
  • “GP-role user”在系统里根本不存在这个属性 —— 一个人不是天生 GP。GP/LP 是逐项目、挂在公司上的。这是最核心的说不清。
  • “Route a logged-in GP-role user”是登录后自动跳转到 Portfolio,还是只提供一个入口点?我们做成侧栏入口,不自动跳。
  • “Scope the view to GP role”具体规则是什么?没给。我们改成“你可见的项目”口径。
  • “No LP view in this release”:那 LP 登录进来是隐藏入口、还是允许看但只显示他能看的?我们不隐藏入口,按可见项目放行。
GP / LP 与账号的关系(为什么 AXI-72 那样写行不通)
1. Linear 假设有一种「GP-role user」—— 好像一个人天生就是 GP,登录后就看“他的 GP 账户”下所有楼。但我们系统里没有“账户级的 GP/LP 身份”这个东西。
2. 在我们的数据里,GP/LP 是「逐项目的资本结构」:每个项目里可以配置一堆公司,某家公司在 A 项目充当 GP、在 B 项目可以充当 LP。也就是说“是 GP 还是 LP”是跟着“项目 + 公司”走的,不是跟着“人/账号”走的。
3. 所以同一个人完全可能在这个项目是 GP、在那个项目是 LP。用一个账户级的“他是 GP 还是 LP”标志去判断,本身就是错的。
4. 我们的处理:Portfolio View 的可访问范围 = 你在「Projects 列表」里本来就能看到的项目(你自己拥有的 + 你作为 manager 管理的下属的)。既贴合“看自己名下这一篮子 deal”的意图,又不依赖一个并不存在的“GP 角色”。
5. 如果产品上确实要“GP 视角”,需要先在账号上定义一个明确的 GP/LP 属性(并回答“同一个人不同项目不同角色”怎么办)—— 这是需求要先想清楚的地方。
MoM %
No data
Select projects and click Generate