ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

CRM需求分析文档实战指南:角色权限、业务域划分与学生项目落地要点

CRM需求分析文档实战指南:角色权限、业务域划分与学生项目落地要点

简介:本资源是一份面向企业信息化建设人员、软件需求分析师及CRM系统开发者的专业级需求分析设计文档,聚焦客户关系管理系统的功能定义与架构规划,解决销售流程自动化、客户数据整合与业务流程优化等核心问题。文档内容完整覆盖引言、任务概述、功能需求、用例描述、数据流图、实体关系图及界面原型设计,特别包含用户组织结构映射、业务对象术语定义、软硬件运行环境要求及实施约束条件等实战细节,具备直接指导系统开发落地的工程价值。资源为单文件Word文档(.doc),共1个文件,大小1.66MB,格式规范、排版清晰,便于阅读与二次编辑。目前已有188人学习下载,适合中高级IT从业者开展需求调研、撰写同类文档或作为高校信管/软件工程课程的案例参考。

1. 这份 CRM 需求分析文档,不是模板套用的“纸面功夫”,而是能直接撑起毕设答辩、课设交付甚至小型企业落地的骨架

你手头这份《CRM客户关系管理需求分析设计文档》,表面看是2009年某高校实训班(NT10班)产出的旧版材料,但它的价值恰恰藏在“过时”的细节里——它没用云原生、微服务、低代码这些热词包装,却老老实实写清了:谁在用、用在哪、怎么分权、数据怎么流、界面怎么交互、连下拉框该不该做都标了注释。这种“笨功夫”,正是学生做毕设最缺的“真实感”:不是从网上抄个UML图就交差,而是真有人站在销售主管、就业专员、系统管理员三个角色背后,一笔一划画出审批流、日程树、邮件收发闭环。它适合三类人:一是正在赶毕设 deadline 的同学,需要一份结构完整、逻辑自洽、能过导师初审的“需求基线”;二是做课设小组长的同学,要带着组员分工——客户模块谁做、审批流谁调、邮件配置谁测;三是刚入行的初级实施顾问,想看看一个真实(哪怕轻量)CRM系统,需求文档到底该落到什么颗粒度。别被“SQL Server 2000”“WebSphere 6.1”吓退,这些是时代烙印,而它里面关于角色权限隔离、客户-日程-邮件三者关联、审批状态机流转的设计逻辑,今天写 Spring Boot + Vue 的项目,照样得照着这个思路搭。


2. 总体架构设计:三层结构与四个核心业务域的职责划分

这份需求文档虽未明说架构,但从功能模块、运行环境、接口要求中可反向推演出清晰的分层逻辑。它不是单体大泥球,也不是盲目上微服务,而是典型的“表现层–业务逻辑层–数据访问层”三层架构,且每一层都服务于明确的业务域。我带过几个类似规模的校企合作项目,发现学生最容易犯的错,就是把所有功能堆在 Controller 里,结果改个审批状态要动五六个文件。而这份文档用“角色+功能+数据流向”三重约束,天然倒逼出合理的分层。

2.1 系统角色与权限边界:不是RBAC模型,而是“机构树+岗位+操作粒度”三维控制

文档反复强调:“销售部门只能对自己管理范围内的系统进行管理”“系统管理员可在任何机构下创建用户,机构管理员只能在自己机构下新建用户”。这不是一句空话,它定义了一套比标准 RBAC 更贴近业务的权限模型:

  • 机构树(Organization Tree):以“万策对外机构”为根,向下分销售部、就业部、系统维护部;每个部门可再设子部门(如销售部→华东区→上海组)。这棵树不是静态组织图,而是权限作用域的容器。
  • 岗位(Position):文档中称“工作组”,实际是角色实例化。例如“销售主管”不是全局角色,而是“销售部→华东区”下的一个具体岗位,其审批权限仅限本机构内业务员提交的申请。
  • 操作粒度(Operation Granularity):权限控制到按钮级。比如“删除已发短信”(5.2.5)和“删除我的申请”(5.2.10)是两个独立权限点,不能因为有“删除”权限就默认拥有全部删除能力。

提示:实现时千万别用@PreAuthorize("hasRole('SALES_MANAGER')")这种粗粒度注解。我一般会建一张role_org_permission表,字段包括role_id,org_id,permission_code,permission_desc。当用户点击“删除我的申请”时,后端先查当前用户所属机构ID,再查该机构下该角色是否拥有PERM_DELETE_MY_APPLICATION权限。这样,华东区主管删不了华北区的申请,逻辑清清楚楚。

2.2 四大核心业务域:客户、日程、邮件、审批,彼此耦合但边界清晰

文档将功能划为四大块(3.2节),每一块都承担明确的业务语义,且相互之间通过“关联客户”建立弱耦合:

业务域核心实体关键关联点典型业务规则
客户信息管理customer,customer_group所有日程、邮件、审批记录均含customer_id外键销售人员只能查看/编辑自己名下客户(3.3.1.1 备选流)
日程安排daily_task,weekly_plan,monthly_schedulecustomer_id,creator_id,assignee_id日日程按天展示,周日程按周一至周日分块,月日程按日历格展示(3.3.1.1 基本事件流)
邮件系统email,email_account,email_foldersender_id,receiver_id,related_customer_id收件箱/发件箱/废件箱三态分离,支持导出Excel、打印(5.2.13–5.2.17)
审批管理approval_application,approval_recordapplicant_id,approver_id,related_customer_id,status审批状态仅允许“同意/不同意”,通过后不可修改(3.3.1.4 后置条件)

这种划分避免了“大客户表”陷阱——即把所有字段塞进一张customer表。我见过太多毕设项目,客户表里硬塞了“最后联系时间”“下次跟进日期”“审批状态”,结果日程改了时间,客户表也要同步更新,事务一多就出错。而这份文档的思路是:日程归日程管,客户归客户管,两者靠外键关联,查的时候 JOIN,改的时候各负其责。

2.3 数据流向与关键接口:WebService 是灵魂,不是摆设

文档2.1节明确:“通过标准的 WebService 为其它软件系统提供统一的权限管理服务”。这意味着它不是一个孤岛系统,而是未来可能被 HR 系统、合同管理系统调用的权限中心。其核心 WebService 接口应包含:

  • getUserPermissions(userId: String, orgId: String): PermissionList
    返回某用户在某机构下的所有可执行操作码(如["CRM_VIEW_CUSTOMER", "CRM_EDIT_TASK"])
  • validateApproval(approvalId: String, action: String): Boolean
    校验审批动作合法性(如“同意”操作是否由指定 approver 发起)
  • syncCustomerData(customerDto: CustomerDto): Result
    供外部系统推送客户变更(需鉴权+幂等处理)

注意:文档2.2.3节强调“不要使用AD或LDAP”,所以权限数据必须全量存在本库。我一般会在数据库加一张ws_api_log表,记录每次 WebService 调用的request_id,api_name,caller_ip,status_code,response_time,方便后期排查跨系统问题。毕设答辩时,老师问“怎么保证接口安全?”,你拿出这张表的设计,比背OAuth2.0原理更有说服力。


3. 功能模块实现:从用例到代码的关键落点与配置示例

文档3.3.1节的用例描述(CRM101–CRM305)是全文最扎实的部分。它没写“系统应具备高可用性”,而是写“点击‘日日程’进入界面,弹出窗口填主题、启始时间、内容、关联客户”。这种颗粒度,正是你写代码时最需要的输入。下面我以“日程安排”和“邮件帐号配置”两个高频模块为例,给出可直接复用的实现要点。

3.1 日程安排模块:四类日程的共性抽象与差异化渲染

文档将日程拆为日常事务、日日程、周日程、月日程(CRM101–CRM104),表面看是四个功能,实则共享同一套底层模型。我建议用“策略模式+模板方法”实现,避免重复造轮子:

// 统一日程实体(简化版) public class Schedule { private Long id; private String title; // 主题 private LocalDateTime startTime; // 启始时间(精确到分钟) private String content; // 内容 private Long customerId; // 关联客户ID private Long creatorId; // 创建人 private String scheduleType; // 'DAILY', 'WEEKLY', 'MONTHLY', 'TASK' // getter/setter... } // 日程渲染策略接口 public interface ScheduleRenderer { /** * 渲染日程列表(前端所需JSON结构) * @param schedules 日程列表 * @param context 渲染上下文(如:日视图的date,周视图的weekStart) * @return 渲染后的DTO列表 */ List<ScheduleDto> render(List<Schedule> schedules, Map<String, Object> context); } // 日视图渲染器实现 @Component public class DailyScheduleRenderer implements ScheduleRenderer { @Override public List<ScheduleDto> render(List<Schedule> schedules, Map<String, Object> context) { LocalDate targetDate = (LocalDate) context.get("date"); return schedules.stream() .filter(s -> DateUtils.isSameDay(s.getStartTime(), targetDate)) .map(this::toDto) .collect(Collectors.toList()); } private ScheduleDto toDto(Schedule s) { ScheduleDto dto = new ScheduleDto(); dto.setId(s.getId()); dto.setTitle(s.getTitle()); dto.setStartTime(s.getStartTime().toLocalTime()); // 日视图只显示时间 dto.setContent(s.getContent()); dto.setCustomerId(s.getCustomerId()); return dto; } }

设计说明:scheduleType字段是关键。它让同一张schedule表支撑四种日程,避免建daily_schedule,weekly_schedule等四张表。查询时,DAO 层根据scheduleType和上下文参数(如date,weekStart,month)动态拼接 WHERE 条件。前端调用/api/schedules/daily?date=2024-06-15时,后端注入context.put("date", LocalDate.parse("2024-06-15")),交由DailyScheduleRenderer处理。这样,新增“季度日程”只需加一个QuarterlyScheduleRenderer,不动核心逻辑。

3.2 邮件帐号配置模块:安全存储密码与SMTP动态适配

文档5.2.17节要求“邮件帐号配置”,但没提密码怎么存。这是学生项目最常翻车的点——把邮箱密码明文存数据库。文档2.2.2节写的是“Windows XP SP2 + SQL Server 2000”,当时可能真这么干,但现在必须加密。我推荐 AES-128-CBC 加密(密钥由 Spring Bootapplication.yml中的mail.encryption.key配置),并强制要求 SMTP 配置项必须校验连通性:

# application.yml 片段 mail: encryption: key: 32-byte-aes-key-must-be-exactly # 32字节Base64密钥 smtp: host: smtp.exmail.qq.com port: 465 username: ${MAIL_USERNAME} password: ${MAIL_PASSWORD} # 环境变量注入,非明文
// 邮件账号实体(密码字段加密存储) @Entity @Table(name = "email_account") public class EmailAccount { @Id private Long id; private String username; // 明文,用于显示 @Column(name = "encrypted_password") private String encryptedPassword; // AES加密后Base64字符串 private String smtpHost; private Integer smtpPort; private Boolean useSsl; // true for port 465, false for 587 // 密码解密方法(仅在发信时调用) public String decryptPassword() { return AesUtil.decrypt(encryptedPassword, getEncryptionKey()); } private String getEncryptionKey() { return environment.getProperty("mail.encryption.key"); } } // SMTP连通性测试服务 @Service public class SmtpConnectivityService { public boolean testConnection(EmailAccount account) { try { Properties props = new Properties(); props.put("mail.smtp.host", account.getSmtpHost()); props.put("mail.smtp.port", account.getSmtpPort().toString()); props.put("mail.smtp.auth", "true"); if (Boolean.TRUE.equals(account.getUseSsl())) { props.put("mail.smtp.ssl.enable", "true"); } else { props.put("mail.smtp.starttls.enable", "true"); } Session session = Session.getInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication( account.getUsername(), account.decryptPassword() // 此处解密 ); } }); Transport transport = session.getTransport("smtp"); transport.connect( account.getSmtpHost(), account.getSmtpPort(), account.getUsername(), account.decryptPassword() ); transport.close(); return true; } catch (Exception e) { log.error("SMTP connection test failed for account {}", account.getUsername(), e); return false; } } }

参数说明:useSsl字段至关重要。QQ邮箱企业版用 465 端口(SSL),网易邮箱用 587 端口(STARTTLS),如果前端配置页面不区分,后端硬写props.put("mail.smtp.ssl.enable", "true"),就会导致网易邮箱连不上。所以EmailAccount表必须有use_ssl列,前端配置页提供“SSL加密”和“TLS加密”两个单选按钮。毕设演示时,当场测通 SMTP,比讲一百遍“高内聚低耦合”都管用。


4. 关键避坑指南:学生项目最容易翻车的5个点及血泪解决方案

这份需求文档写于2009年,但里面埋的坑,今天的学生一个都没躲开。我带过的毕设里,80%的延期和答辩卡壳,都源于这几个看似简单、实则致命的点。以下全是真实踩过的坑,按“现象→原因→解决”结构整理,每一条都对应文档中的具体条款。

4.1 现象:登录后,销售主管能看到所有部门的客户,而非仅本机构

原因:权限校验只做了角色判断(如isSalesManager()),没校验org_id。文档1.2.3节明确“用户组织结构”和2.2.3节“销售部门只能对自己管理范围内的系统进行管理”,但代码里漏了机构过滤。
解决:在所有客户查询接口(如GET /api/customers)的 Service 层,强制注入当前用户所属机构ID,并作为 WHERE 条件。

// 错误示范(只校角色) List<Customer> customers = customerMapper.selectAll(); // 全查! // 正确示范(加机构过滤) Long currentOrgId = getCurrentUserOrgId(); // 从SecurityContext或ThreadLocal获取 List<Customer> customers = customerMapper.selectByOrgId(currentOrgId);

血泪经验:我在某校毕设答辩现场,看到同学演示“销售主管查看客户”,老师当场问:“如果你们公司有北京、上海、广州三个销售部,上海主管能看广州客户吗?”同学愣住。后来他加了org_id过滤,当场通过。

4.2 现象:日程安排里“关联客户”下拉框为空,或显示了其他部门的客户

原因:文档2.2.3节要求“能做成下来列表的选项一定做成下拉列表”,但前端请求客户列表时,没传org_id参数,后端也未做机构过滤,导致查出全库客户。更糟的是,有些同学用SELECT * FROM customer塞进下拉框,客户一多直接卡死。
解决:下拉框数据接口必须带分页和机构过滤,且前端禁用v-model双向绑定大数据量列表,改用远程搜索(Remote Search)。

// Vue组件中 <el-select v-model="form.customerId" filterable remote :remote-method="loadCustomers" :loading="customerLoading" > <el-option v-for="item in customerOptions" :key="item.id" :label="item.name" :value="item.id" /> </el-select> // loadCustomers 方法 loadCustomers(query) { if (query.length < 2) return; // 至少输2个字才查 this.customerLoading = true; api.getCustomers({ orgId: this.currentUser.orgId, // 必传机构ID keyword: query, page: 1, size: 20 }).then(res => { this.customerOptions = res.data; }).finally(() => this.customerLoading = false); }

4.3 现象:审批通过后,申请人还能修改/删除申请记录

原因:文档3.3.1.4节后置条件写得清清楚楚:“审批通过后就不能对结果进行删除,修改。只能有查看的功能”,但代码里只做了前端按钮隐藏(v-if="status !== 'APPROVED'"),后端接口完全没校验,抓个包就能绕过。
解决:后端接口必须做状态守门(State Guard)。在updateApplication()和deleteApplication()方法开头,强制校验:

public void updateApplication(Long appId, ApplicationUpdateDto dto) { Application app = applicationMapper.selectById(appId); if ("APPROVED".equals(app.getStatus()) || "REJECTED".equals(app.getStatus())) { throw new BusinessException("已审批的申请不可修改"); } // ...后续逻辑 }

玄学提醒:毕设答辩时,老师最爱用 Postman 直接调后端接口测试。如果你只做前端限制,老师一试就崩,印象分直接归零。

4.4 现象:导出邮件Excel时中文乱码,或日期格式错误

原因:文档5.2.16节要求“导出邮件”,但用new HSSFWorkbook()(POI 3.x)处理 Excel,不设置编码和单元格格式。更常见的是,用SimpleDateFormat解析数据库里的datetime字段,时区搞错。
解决:统一用 POI 5.x 的XSSFWorkbook(.xlsx格式),并显式设置字体和日期格式:

XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("邮件列表"); XSSFFont font = workbook.createFont(); font.setFontName("微软雅黑"); font.setFontHeightInPoints((short) 10); XSSFCellStyle style = workbook.createCellStyle(); style.setFont(font); style.setDataFormat(workbook.createDataFormat().getFormat("yyyy-mm-dd hh:mm:ss")); Row headerRow = sheet.createRow(0); for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(style); } // ...填充数据行,每行cell均 setCellStyle(style)

4.5 现象:短信发送失败,日志里只有一句“发送异常”,找不到具体错在哪

原因:文档5.2.16–5.2.18节涉及短信管理,但没提日志规范。学生常写e.printStackTrace()或log.error("send sms error"),出了问题两眼一抹黑。
解决:短信发送必须记录结构化日志,包含关键上下文:

log.info("SMS_SEND_START | phone:{} | content:{} | templateCode:{} | userId:{}", phone, content, templateCode, userId); try { // 发送逻辑 log.info("SMS_SEND_SUCCESS | phone:{} | msgId:{} | userId:{}", phone, msgId, userId); } catch (Exception e) { log.error("SMS_SEND_FAILED | phone:{} | content:{} | userId:{} | errorMsg:{}", phone, content, userId, e.getMessage(), e); // 记录完整异常栈 }

后悔药:我带的一个小组,上线前一周短信总失败,就靠这条日志定位到是运营商模板审核未通过,而不是代码问题。没有它,至少多花三天。


5. 数据模型与接口设计:ER图落地、API契约与验收检查表

文档3.3.2节提到“数据概念结构图(实体—关系图)”,3.3.3节有“系统业务流程图”,但原文未附图。作为一份能交付的方案,我们必须补全这部分——不是画个漂亮UML充数,而是给出可建表、可生成MyBatis XML、可被Postman调通的真实数据契约。

5.1 核心实体ER关系:聚焦客户、日程、邮件、审批四张主表

基于文档功能描述,提炼出四张核心表及其关键字段(省略审计字段如create_time,update_time):

customer客户表

字段名类型说明文档依据
idBIGINT PK主键—
nameVARCHAR(100)客户名称3.3.1.1 “关联客户”
mobileVARCHAR(20)手机号5.2.16 短信管理
org_idBIGINT所属机构ID(外键)1.2.3 用户组织结构
owner_idBIGINT当前负责人ID(销售员ID)3.1 总体功能需求

schedule日程表

字段名类型说明文档依据
idBIGINT PK主键—
titleVARCHAR(200)主题3.3.1.1 基本事件流
start_timeDATETIME启始时间同上
contentTEXT内容同上
customer_idBIGINT关联客户ID同上
creator_idBIGINT创建人ID同上
assignee_idBIGINT指派人IDCRM205 指派人员
schedule_typeVARCHAR(20)'DAILY','WEEKLY','MONTHLY','TASK'3.2 功能划分

email邮件表

字段名类型说明文档依据
idBIGINT PK主键—
subjectVARCHAR(200)主题5.2.12 写邮件
bodyLONGTEXT邮件正文同上
sender_idBIGINT发件人ID5.2.13 收件箱
receiver_idBIGINT收件人ID同上
folder_typeVARCHAR(20)'INBOX','SENT','TRASH'5.2.13–5.2.15
statusVARCHAR(20)'DRAFT','SENT','READ'5.2.16 查询邮件
related_customer_idBIGINT关联客户ID5.2.12 写邮件

approval_application审批申请表

字段名类型说明文档依据
idBIGINT PK主键—
titleVARCHAR(200)主题3.3.1.4 基本事件流
contentTEXT申请内容同上
applicant_idBIGINT申请人ID同上
approver_idBIGINT审批人IDCRM114 我的审批
statusVARCHAR(20)'PENDING','APPROVED','REJECTED'3.3.1.4 后置条件
related_customer_idBIGINT关联客户ID同上

关系说明:四张表通过org_id,customer_id,user_id形成网状关联,但无循环依赖。customer是中心实体,schedule,email,approval_application均以customer_id为外键,体现“客户为中心”的CRM本质。建表时,所有外键必须加索引(如idx_customer_org),否则关联查询极慢。

5.2 RESTful API契约:按文档用例编号定义可测试端点

文档3.2节列出了用例编号(CRM101–CRM305),我们将其映射为标准REST API,确保每个用例都有对应端点,且命名符合文档描述:

用例编号用例名称HTTP方法URL路径请求体示例文档依据
CRM101日常事务GET/api/schedules/tasks—3.3.1.2 基本事件流
CRM102日日程GET/api/schedules/daily{ "date": "2024-06-15" }3.3.1.1 基本事件流
CRM103周日程GET/api/schedules/weekly{ "weekStart": "2024-06-10" }同上
CRM104月日程GET/api/schedules/monthly{ "year": 2024, "month": 6 }同上
CRM107发邮件POST/api/emails/send{ "to": "a@b.com", "subject": "...", "body": "..." }3.3.1.5 基本事件流
CRM108收件箱GET/api/emails/folders/INBOX—3.3.1.6 基本事件流
CRM109废件箱GET/api/emails/folders/TRASH—3.3.1.8 基本事件流
CRM114我的审批GET/api/approvals/my—3.3.1.3 基本事件流
CRM115我的申请GET/api/approvals/my-applications—3.3.1.4 基本事件流
CRM205指派人员POST/api/schedules/assign{ "scheduleId": 123, "userId": 456 }CRM205 用例描述

设计说明:URL 路径严格遵循 REST 原则,资源名词用复数(schedules,emails,approvals),动作用 HTTP 方法表达(GET 查、POST 增、PUT 改、DELETE 删)。/folders/INBOX这种路径,比/inbox更易扩展(未来加OUTBOX只需改枚举值)。所有接口必须返回标准 JSON 结构:{ "code": 200, "message": "success", "data": {...} },便于前端统一处理。

5.3 验收检查表:对照文档条款逐条验证,答辩前必过清单

毕设答辩不是考你背了多少理论,而是看你有没有把文档里的白纸黑字,变成可运行、可演示、可解释的系统。我给学生定的硬性验收标准,就是拿着这份检查表,一项项打钩:

序号验收项文档依据演示方式是否通过
1登录后,销售员只能看到自己名下客户(owner_id = current_user_id)3.3.1.1 备选流登录销售员A,查客户列表;登录销售员B,查客户列表;确认数据隔离□
2日日程界面,选择日期后,只显示该日的日程(DATE(start_time) = ?)3.3.1.1 基本事件流在日视图选6月15日,列表只显示6月15日的日程□
3审批通过后,申请人无法修改/删除该申请(后端拦截)3.3.1.4 后置条件用Postman调PUT /api/approvals/{id},传已审批状态,返回400错误□
4邮件帐号配置页,输入SMTP信息后,点击“测试连接”按钮,弹出成功/失败提示5.2.17 邮件帐号配置填QQ邮箱配置,点测试;填错误密码,点测试;观察提示□
5导出邮件Excel,打开后中文不乱码,日期格式为“yyyy-MM-dd HH:mm:ss”5.2.16 查询邮件点“导出Excel”,用Excel打开,检查编码和格式□
6短信发送日志,包含手机号、内容、错误信息(如有)5.2.16–5.2.18 短信管理查看logs/app.log,搜索SMS_SEND_,确认字段齐全□
7系统管理员可创建任意机构用户,机构管理员只能创建本机构用户2.2.3 其它要求管理员登录,创建华北区用户;华北区管理员登录,尝试创建华东区用户,应失败□

提示:答辩前夜,我要求学生把这张表打印出来,对着系统一项项操作,录屏存档。老师问“怎么保证权限不越界?”,你直接打开录屏,播放第1项和第7项的操作过程,比讲十分钟RBAC模型都直观。从那以后我每次带毕设,都强制走一遍这个 checklist,没一次被老师挑出逻辑漏洞。

希望帮到你。

本文还有配套的精品资源,点击获取

返回列表