Skip to content

docs(site): lead round-robin doors, product price rules, campaign end date and conversion attribution follow the code (#2362) - #2364

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-3dm407
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-3dm407

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Irene · project thread

Fixes #2362

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么: 文档站(content/docs)三组页面、各三种语言共 9 个文件:设置清单的线索轮询入口、产品的价格规则、营销活动的结束日期与线索转化归因。只改文字,不改任何行为。
  • 为什么改: 这四处说法与 18.2.0 的实测相反(例如说 CSV 导入会进轮询、成本高于标价只警告、转化线索会把收入归给营销活动),而应用内帮助页已经写对了,站点自相矛盾。
  • 风险与回滚: 纯文档,无数据影响;回滚即还原这 9 个 .mdx 和一个 changeset。
  • 先看: content/docs/marketing/campaigns.mdx(归因段改动最大,字段名由 Source Campaign 改为真实标签 Campaign)、content/docs/administration/setup.mdx、content/docs/revenue/products.mdx。
  • 两分钟验证: 打开文档站 Marketing → Campaigns 的 “Attribution” 一节,应读到“转化线索不会填写 Campaign,需要手动设置”。
  • 需要你做的: 无,席位落地。

What changes

The docs site now states what the app does, in English, zh-Hans and zh-Hant. ⛔ No behaviour change.

Row Page Was Now (measured below)
1 administration/setup §8 Lead routing an ownerless lead from web-to-lead, CSV import or API capture goes to the round-robin web-to-lead is the one door into the round-robin; a lead created in the app, sent through the API (session or key), or imported from CSV/JSON is owned by its writer. Links Import your own data (en: its #owners section; zh pages link the page and name the 关于负责人 / 關於負責人 section, which has no English anchor id)
2 revenue/products "List price must be greater than zero"; "Cost cannot exceed list price — warning only"; the Pricing fields note "the system warns you" a negative List Price is refused and zero is accepted; Cost above List Price is refused; Cost equal to List Price saves
3 marketing/campaigns Built-in rules "End date must be on or after the start date" End Date must be after Start Date; a same-day campaign is refused
4 marketing/campaigns Attribution, and the matching sales-rep tip converting a lead from a campaign credits the revenue back to the campaign; the field is called Source Campaign conversion does not set Campaign on the opportunity it creates (the conversion screen has no such field), so the deal is credited only once someone sets Campaign on it. The field is named by its shipped label, Campaign (crm_opportunity.crm_campaign, label: 'Campaign')

The in-app pages (src/docs/crm_sales_leads.md, src/revenue/docs/crm_revenue_products.md, src/marketing/docs/crm_marketing_campaigns.md) already said this; the site now agrees with them, written fresh, not copied.

Tests

  • No docs guard pinned any of the old sentences, so no expectation changed.
  • npx vitest run test/docs-*.test.ts on 737e0f0: Test Files 31 passed (31), Tests 585 passed (585).
  • pnpm verify on 737e0f0: exit 0 (validate, typecheck, lint, hygiene, hygiene:tokens, build, test); Test Files 242 passed (242), Tests 4612 passed | 1 skipped (4613).

Acceptance notes

Verification

All probes on a fresh objectstack dev (ObjectStack 18.2.0, hotcrm origin/main 6c52f22, SQLite file DB, --seed-admin, staffed with pnpm demo:staff; rep pool = na.rep + eu.rep), 2026-10-28.

Row 1: lead doors (re-runs #2360's probes, plus a writer outside the rep pool)
anonymous POST /api/v1/forms/contact-us/submit #1 → 201; lead owner = eu.rep (pool rep)
anonymous POST /api/v1/forms/contact-us/submit #2 → 201; lead owner = eu.rep (pool rep)
POST /api/v1/data/crm_lead as admin, no owner → 201; owner = admin (writer)
POST /api/v1/data/crm_lead as sales.manager, no owner → 201; owner = sales.manager (writer, not in pool)
POST /api/v1/data/crm_lead/import (json, blank owner) as admin → 200; owner = admin (writer)
POST /api/v1/data/crm_lead/import (json, blank owner) as sales.manager → 200; owner = sales.manager (writer, not in pool)
POST /api/v1/data/crm_lead/import (csv, crm_lead_import mapping, blank owner) as sales.manager → 200; owner = sales.manager (writer, not in pool)
Row 2: product price rules
POST crm_product list_price 0 → 201
POST crm_product list_price -1 → 400 VALIDATION_FAILED "List Price must be ≥ 0"
PATCH crm_product list 9000 cost 9500 → 400 VALIDATION_FAILED "List Price (9000) must be greater than or equal to Cost (9500)."  (product.hook.ts)
PATCH crm_product list 9000 cost 9000 → 200
Row 3: campaign dates
POST crm_campaign start 2026-11-02, end 2026-11-02 → 400 VALIDATION_FAILED "End Date must be after Start Date"
POST crm_campaign start 2026-11-02, end 2026-11-03 → 201
Row 4: lead conversion and the campaign
campaign (In Progress) → 201; qualified lead → 201; campaign member (lead, Responded) → 201
POST /api/v1/automation/lead_conversion/trigger → 200 paused; screen fields: createOpportunity, opportunityName, opportunityAmount, closeDate
resume (createOpportunity true, amount 50000) → 200, result screen "Lead Converted"
lead after: status=converted, converted_opportunity set
created opportunity: crm_campaign=null, lead_source=web, amount=50000
campaign after: num_converted_leads 1, num_opportunities 0
PATCH crm_opportunity crm_campaign = the campaign → 200; campaign after: num_opportunities 1

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8VVAjhzCx8F4c3imwn9RP

…ign end date and conversion attribution

Setup: only web-to-lead reaches the lead round-robin; an app, API or file
import lead is owned by its writer (links the import guide's Owners section).
Products: zero list price is accepted, negative refused; cost above list price
is refused, not warned. Campaigns: end date must be after start date (same-day
refused); lead conversion does not set Campaign on the new opportunity, and the
field's label is Campaign, not Source Campaign. en, zh-Hans and zh-Hant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAjhzCx8F4c3imwn9RP
@vercel

vercel Bot commented Oct 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Oct 28, 2026 8:36am UTC

Request Review

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 28, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

Verdict: ACCEPT · repo:hotcrm seat 1 · huangyiirene · session session_01J8VVAnPkgK6CWrJa6t7Fk5 · 2026-10-28T08:38Z · head 737e0f0
Implemented-by: card thread session session_01J8VVAjhzCx8F4c3imwn9RP (report 6464464275 on #2362). Reviewed-by: the seat, against the 10-file diff and hotcrm origin/main 6c52f22.

  • Shape:
    • Draft PR, base main, assignee huangyiirene. The body reads Fixes #2362.
    • No governed path is touched.
    • The diff stays within claim 6464128368: three site pages in en, zh-Hans and zh-Hant, plus a changeset. No guard pinned an old sentence.
    • git merge-tree against 6c52f22 is clean.
  • Ruling held: the text follows the code, with no behaviour change. All four rows were re-measured on 18.2.0 at 6c52f22, and all of them hold.
    1. setup: web-to-lead is the one way into the round-robin. The app, the API (session or API key) and CSV or JSON import keep their writer as owner. The page links importing-your-data#owners, and that anchor exists (:174).
    2. products: a negative List Price is refused and zero is accepted. Cost above List Price is refused, and an equal cost saves.
    3. campaigns, end date: an end date equal to the start date is refused.
    4. campaigns, attribution: conversion does not fill the opportunity's Campaign lookup, which is set by hand. The page now uses the field's real label, Campaign (opportunity.object.ts:361), where it said "Source Campaign", and the sales-rep tip changes with it.
  • Gates:
    • pnpm verify exit 0 at 737e0f0: 242 files, 4612 passed, 1 skipped.
    • The docs guards pass 585 of 585.
    • CI on 737e0f0: 8 of 9 check runs are success, link-check included. Build and Test (22.x) is still running.
  • Out of scope: two notes, neither needing a card.
    • A conversion's member and counter updates arrive a few seconds later. The site's "kept current" still holds.
    • The setup checklist line is still true for web-to-lead.
  • Landing: non-governed. The seat flips the PR to ready and arms auto-merge in this stroke.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 08:39
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 353dace Oct 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

2 participants