Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/agents/business-logic-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ const ValidateDiscount: Hook = {

if (quote.DiscountPercent > maxDiscount) {
throw new Error(
`折扣不能超过${maxDiscount}%` +
`金额超过10万的订单最多可打8折,其他订单最多9折。`
`Discount cannot exceed ${maxDiscount}%. ` +
`Orders over 100,000 allow up to 20% discount; smaller orders allow up to 10% discount.`
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion .github/agents/metadata-developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default MyObject;
{
name: 'AccountId',
type: 'lookup',
label: '客户',
label: 'Account',
referenceTo: 'Account',
required: true
}
Expand Down
4 changes: 2 additions & 2 deletions .github/agents/ui-developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const AccountListView: ViewSchema = {
filters: {
default: [['Type', '=', 'Customer']],
quickFilters: [
{ label: '我的客户', filter: [['OwnerId', '=', '$currentUser']] },
{ label: '高价值', filter: [['Rating', '=', 'Hot']] }
{ label: 'My Customers', filter: [['OwnerId', '=', '$currentUser']] },
{ label: 'High Value', filter: [['Rating', '=', 'Hot']] }
]
},
actions: ['New', 'Edit', 'Delete', 'Export']
Expand Down
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# GitHub Copilot Instructions for HotCRM

You are an expert developer and CTO working on **HotCRM**, a world-class enterprise CRM system built on the **@objectstack/spec** protocol. Your goal is to combine Salesforce-level functionality with Apple/Linear-level user experience.
You are an expert developer and CTO working on **HotCRM**, a world-class enterprise CRM system built on the **@objectstack/spec v0.6.1** protocol. Your goal is to combine Salesforce-level functionality with Apple/Linear-level user experience.

## Core Architecture Principles & Protocol

1. **Metadata Driven Architecture (Type-Safe)**:
- All business objects are defined natively in **TypeScript** (`*.object.ts`).
- strictly typed using `@objectstack/spec` schemas.
- strictly typed using `@objectstack/spec v0.6.1` schemas.
- **NEVER** use YAML or JSON for metadata anymore.

2. **ObjectQL (No SQL)**:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

> A world-class Customer Relationship Management system built on @objectstack/spec v0.6.1 protocol with Salesforce-level functionality and Apple/Linear-level UX.

> 📝 **Latest Updates**: See [UPGRADE_NOTES.md](UPGRADE_NOTES.md) for information about the v0.6.1 upgrade and runtime migration status.

## 🌟 Overview

HotCRM is a **comprehensive, AI-native enterprise CRM** system covering the complete Lead-to-Cash lifecycle. Built on the @objectstack/spec v0.6.1 protocol, it delivers:
Expand Down Expand Up @@ -375,7 +377,7 @@ HotCRM implements a comprehensive enterprise CRM system organized into **5 major
### 4. 🟣 Platform Foundation

**Metadata-Driven Architecture**
- All objects defined in declarative YAML
- All objects defined natively in TypeScript (`.object.ts`)
- ObjectQL query language for type-safe data access
- Dynamic field and layout management
- Custom validation rules
Expand Down
38 changes: 19 additions & 19 deletions content/docs/ai/capabilities.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ The lead scoring model evaluates multiple factors:
{
name: 'LeadScore',
type: 'number',
label: '线索评分',
label: 'Lead Score',
precision: 0,
min: 0,
max: 100,
readonly: true,
description: 'AI 自动计算的线索质量分数 (0-100)'
description: 'AI-calculated lead quality score (0-100)'
}
```

Expand Down Expand Up @@ -111,27 +111,27 @@ Predict the probability of winning a deal based on historical data and current o
{
name: 'AIWinProbability',
type: 'percent',
label: 'AI 赢单概率',
label: 'AI Win Probability',
readonly: true,
description: 'AI 预测的赢单概率'
description: 'AI-predicted win probability'
},
{
name: 'AIRiskFactors',
type: 'textarea',
label: 'AI 风险因素',
label: 'AI Risk Factors',
readonly: true,
description: 'AI 识别的潜在风险'
description: 'AI-identified potential risks'
},
{
name: 'AINextStepSuggestion',
type: 'text',
label: 'AI 建议下一步',
label: 'AI Next Step Suggestion',
readonly: true
},
{
name: 'AICompetitiveIntel',
type: 'textarea',
label: 'AI 竞争情报',
label: 'AI Competitive Intelligence',
readonly: true
}
```
Expand Down Expand Up @@ -253,26 +253,26 @@ Automatically transcribe meeting recordings and phone calls to text with action
{
name: 'Transcription',
type: 'textarea',
label: '会议转录',
label: 'Meeting Transcription',
readonly: true,
length: 32000
},
{
name: 'TranscriptionSummary',
type: 'textarea',
label: 'AI 会议摘要',
label: 'AI Meeting Summary',
readonly: true
},
{
name: 'AIActionItems',
type: 'textarea',
label: 'AI 提取行动项',
label: 'AI Extracted Action Items',
readonly: true
},
{
name: 'AISentiment',
type: 'select',
label: 'AI 情感分析',
label: 'AI Sentiment Analysis',
readonly: true,
options: [
{ label: '😊 Positive', value: 'Positive' },
Expand Down Expand Up @@ -350,7 +350,7 @@ Automatically categorize cases, leads, and other records based on content analys
{
name: 'AISuggestedType',
type: 'select',
label: 'AI 建议类型',
label: 'AI Suggested Type',
readonly: true,
options: [
{ label: '🐛 Problem', value: 'Problem' },
Expand All @@ -362,7 +362,7 @@ Automatically categorize cases, leads, and other records based on content analys
{
name: 'AISuggestedPriority',
type: 'select',
label: 'AI 建议优先级',
label: 'AI Suggested Priority',
readonly: true,
options: [
{ label: 'Critical', value: 'Critical' },
Expand Down Expand Up @@ -421,14 +421,14 @@ Generated Answer + Citations
{
name: 'VectorEmbedding',
type: 'json',
label: '向量嵌入',
label: 'Vector Embedding',
readonly: true,
description: 'AI 生成的语义向量用于相似度搜索'
description: 'AI-generated semantic vector for similarity search'
},
{
name: 'AISummary',
type: 'textarea',
label: 'AI 摘要',
label: 'AI Summary',
readonly: true
}
```
Expand Down Expand Up @@ -502,14 +502,14 @@ The AI considers:
{
name: 'AISuggestedAgent',
type: 'lookup',
label: 'AI 推荐客服',
label: 'AI Suggested Agent',
referenceTo: 'User',
readonly: true
},
{
name: 'AIRoutingReason',
type: 'text',
label: 'AI 路由原因',
label: 'AI Routing Reason',
readonly: true
}
```
Expand Down
10 changes: 5 additions & 5 deletions content/docs/ai/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -127,25 +127,25 @@ HotCRM uses a consistent naming convention for AI-generated fields:
{
name: 'LeadScore',
type: 'number',
label: '线索评分',
label: 'Lead Score',
min: 0,
max: 100,
readonly: true,
description: 'AI 自动计算的线索质量分数 (0-100)'
description: 'AI-calculated lead quality score (0-100)'
}

{
name: 'AISummary',
type: 'textarea',
label: 'AI 线索分析',
label: 'AI Lead Analysis',
readonly: true,
description: 'AI 生成的线索质量分析和建议'
description: 'AI-generated lead quality analysis and recommendations'
}

{
name: 'AIRecommendedAction',
type: 'text',
label: 'AI 推荐行动',
label: 'AI Recommended Action',
readonly: true
}
```
Expand Down
14 changes: 7 additions & 7 deletions content/docs/api-reference/rest-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,8 @@ POST /ai/lead-score/{leadId}
{
"leadId": "lead_123",
"score": 85,
"summary": "高质量线索:公司规模大,资料完整",
"recommendedAction": "立即联系,安排产品演示",
"summary": "High quality lead: Large company, complete profile",
"recommendedAction": "Contact immediately, schedule product demo",
"factors": {
"completeness": 90,
"companyQuality": 85,
Expand Down Expand Up @@ -757,12 +757,12 @@ GET /metadata/objects/{objectName}
```json
{
"name": "Account",
"label": "客户",
"label": "Account",
"fields": [
{
"name": "Name",
"type": "text",
"label": "客户名称",
"label": "Account Name",
"required": true,
"length": 255
}
Expand All @@ -784,9 +784,9 @@ GET /metadata/objects
```json
{
"objects": [
{ "name": "Account", "label": "客户" },
{ "name": "Contact", "label": "联系人" },
{ "name": "Opportunity", "label": "商机" }
{ "name": "Account", "label": "Account" },
{ "name": "Contact", "label": "Contact" },
{ "name": "Opportunity", "label": "Opportunity" }
]
}
```
Expand Down
32 changes: 16 additions & 16 deletions content/docs/development/business-logic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,15 @@ async function handleClosedWon(ctx: TriggerContext): Promise<void> {

// 3. Log activity
await ctx.db.doc.create('Activity', {
Subject: `商机成交: ${opportunity.Name}`,
Subject: `Opportunity Won: ${opportunity.Name}`,
Type: 'Milestone',
Status: 'Completed',
Priority: 'High',
AccountId: opportunity.AccountId,
WhatId: opportunity.Id,
OwnerId: ctx.user.id,
ActivityDate: new Date().toISOString().split('T')[0],
Description: `商机 "${opportunity.Name}" 已成功成交,金额: ${opportunity.Amount?.toLocaleString() || 0}`
Description: `Opportunity "${opportunity.Name}" successfully won, amount: ${opportunity.Amount?.toLocaleString() || 0}`
});
console.log('✅ Activity logged for Closed Won');
}
Expand All @@ -172,15 +172,15 @@ async function handleClosedLost(ctx: TriggerContext): Promise<void> {

// Log activity for lost opportunity
await ctx.db.doc.create('Activity', {
Subject: `商机丢失: ${opportunity.Name}`,
Subject: `Opportunity Lost: ${opportunity.Name}`,
Type: 'Milestone',
Status: 'Completed',
Priority: 'Normal',
AccountId: opportunity.AccountId,
WhatId: opportunity.Id,
OwnerId: ctx.user.id,
ActivityDate: new Date().toISOString().split('T')[0],
Description: `商机 "${opportunity.Name}" 已丢失,金额: ${opportunity.Amount?.toLocaleString() || 0}。原因待分析。`
Description: `Opportunity "${opportunity.Name}" lost, amount: ${opportunity.Amount?.toLocaleString() || 0}. Reason to be analyzed.`
});
console.log('✅ Activity logged for Closed Lost');
}
Expand All @@ -193,15 +193,15 @@ async function logStageChange(ctx: TriggerContext): Promise<void> {
const oldStage = ctx.old?.Stage || 'Unknown';

await ctx.db.doc.create('Activity', {
Subject: `商机阶段变更: ${oldStage} → ${ctx.new.Stage}`,
Subject: `Opportunity Stage Changed: ${oldStage} → ${ctx.new.Stage}`,
Type: 'Stage Change',
Status: 'Completed',
Priority: 'Normal',
AccountId: opportunity.AccountId,
WhatId: opportunity.Id,
OwnerId: ctx.user.id,
ActivityDate: new Date().toISOString().split('T')[0],
Description: `商机阶段从 "${oldStage}" 变更为 "${ctx.new.Stage}"`
Description: `Opportunity stage changed from "${oldStage}" to "${ctx.new.Stage}"`
});
}

Expand Down Expand Up @@ -337,7 +337,7 @@ const ContractBeforeUpdate: HookSchema = {

// Prevent changing activated contract
if (oldContract.Status === 'Activated' && newContract.Status !== 'Activated') {
throw new Error('不能修改已激活的合同状态');
throw new Error('Cannot modify activated contract status');
}

// Require approval for value changes > 10%
Expand All @@ -347,7 +347,7 @@ const ContractBeforeUpdate: HookSchema = {
);

if (change > 0.1 && !newContract.ApprovalStatus) {
throw new Error('合同金额变更超过10%需要审批');
throw new Error('Contract amount change exceeding 10% requires approval');
}
}
}
Expand Down Expand Up @@ -406,7 +406,7 @@ const AccountBeforeDelete: HookSchema = {
});

if (activeOpps.length > 0) {
throw new Error('不能删除有活动商机的客户');
throw new Error('Cannot delete account with active opportunities');
}

// Check for active contracts
Expand All @@ -419,7 +419,7 @@ const AccountBeforeDelete: HookSchema = {
});

if (activeContracts.length > 0) {
throw new Error('不能删除有激活合同的客户');
throw new Error('Cannot delete account with activated contracts');
}
}
};
Expand Down Expand Up @@ -499,14 +499,14 @@ async function calculateLeadScore(lead: any): Promise<{
let action = '';

if (totalScore >= 70) {
summary = '高质量线索:公司规模大,资料完整';
action = '立即联系,安排产品演示';
summary = 'High quality lead: Large company, complete profile';
action = 'Contact immediately, schedule product demo';
} else if (totalScore >= 40) {
summary = '中等质量线索:需要进一步确认需求';
action = '发送邮件了解具体需求';
summary = 'Medium quality lead: Needs further requirement confirmation';
action = 'Send email to understand specific needs';
} else {
summary = '低质量线索:资料不完整或公司规模小';
action = '添加到培育流程';
summary = 'Low quality lead: Incomplete profile or small company';
action = 'Add to nurturing workflow';
}

return { score: totalScore, summary, action };
Expand Down
Loading
Loading