# 1. 项目进度管理
# 1.1 禅道简介
# 1.1.1 基本介绍
禅道是一款国产的开源项目管理软件,它的核心管理思想基于敏捷方法scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。
- 官方网站:https://www.zentao.net/index.html (opens new window)
- 使用手册:https://www.zentao.net/book/zentaopms/38.html (opens new window)
# 1.1.2 禅道安全漏洞
漏洞概述:该漏洞是由于禅道项目管理系统权限认证存在缺陷导致,攻击者可利用该漏洞在未授权的情况下,通过权限绕过在服务器执行任意命令。
项目地址:https://github.com/webraybtl/zentaopms_poc (opens new window)
影响范围:开源版、旗舰版、企业版均有所涉及
禅道系统 | 影响版本 |
---|---|
开源版 | 17.4以下的未知版本<=version<=18.0.beta1 |
旗舰版 | 3.4以下的未知版本<=version<=4.0.beta1 |
企业版 | 7.4以下的未知版本<=version<=8.0.beta1 8.0.beta2 |
# 1.2 禅道部署
# 1.2.1 禅道服务部署
方式一:使用Docker方式部署
$ docker pull idoop/zentao
$ docker run -d -p 7777:80 -p 7776:3306 -e ADMINER_USER="root" -e ADMINER_PASSWD="password" -e BIND_ADDRESS="false" --name zentao idoop/zentao:latest
$ docker logs -f zentao
2
3
方式二:使用一键脚本部署(开源版v18.5)
$ cd /opt // 该一键脚本必须在 /opt 目录操作
$ wget https://www.zentao.net/dl/zentao/18.5/ZenTaoPMS.18.5.zbox_64.tar.gz
$ tar -zxvf ZenTaoPMS.18.5.zbox_64.tar.gz -C /opt
$ /opt/zbox/zbox -ap 7777 -mp 7776 // -ap参数 可以修改Apache的端口,-mp参数 可以修改MySQL的端口
$ /opt/zbox/zbox start // 如果需要停止 /opt/zbox/zbox stop
2
3
4
5
注:如果执行 /opt/zbox/zbox 存在权限不足的问题,使用 sudo 即可。
启动完成后,打开Chrome访问http://ip:7777
地址(默认用户名:admin,密码:123456;数据库用户:root,默认密码:123456)
# 1.2.2 更换数据库
自带的MySQL没有对外暴露数据库的端口,只能网页或命令行访问,非常不便,这里将一键脚本部署方式的MySQL换成自己的(支持MySQL5.x,但不支持8.x)
Step1:先按照官方的方式连接数据库并将sql导出(如果有了可以略过这一步)
$ cd /opt/zbox/auth/
$ ./adduser.sh // 添加用户名及密码
2
登录页的“数据库管理”就是入口,网页访问的账号验证就是刚刚添加的那个。
之后的数据库连接信息填写如下:服务器 127.0.0.1:7776(必须写127.0.0.1,真实IP不行) zentao root / 12345
连上去之后依次点击如下按钮,导出数据文件。
然后在自己的MySQL上创建数据库,导入刚刚的sql数据。
$ CREATE DATABASE zentao DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;
Step2:修改代码去除禅道自带的数据库功能
$ /opt/zbox/zbox stop // 先停止禅道服务
$ cd /opt/zbox/bin/
$ cp zbox.php zbox.php.copy // 把原来的文件拷一份备份
$ vim /opt/zbox/bin/zbox.php
2
3
4
将有关MySQL的指令删除,修改后的脚本如下:
#!/opt/zbox/bin/php
<?php
array_shift($argv);
$flipArgv = array_flip($argv);
$basePath = dirname(dirname(__FILE__));
if($basePath != '/opt/zbox') die("Run it in path /opt/zbox/\n");
if(empty($argv) or isset($flipArgv['--help']) or isset($flipArgv['-h']))
{
echo <<<EOD
Usage: zbox.php {start|stop|restart|status}
Options:
-h --help Show help.
-ap --aport Apache port, default 80.
-mp --mport Mysql port, default 3306.
EOD;
exit;
}
if(is_dir("$basePath/app/zentao/"))
{
`chmod -R 777 $basePath/app/zentao/tmp`;
`chmod -R 777 $basePath/app/zentao/www/data`;
`chmod 777 $basePath/app/zentao/www/`;
`chmod 777 $basePath/app/zentao/config/`;
`chmod -R a+rx $basePath/app/zentao/bin/*`;
}
if(is_dir("$basePath/app/zentaopro/"))
{
`chmod -R 777 $basePath/app/zentaopro/tmp`;
`chmod -R 777 $basePath/app/zentaopro/www/data`;
`chmod 777 $basePath/app/zentaopro/www/`;
`chmod 777 $basePath/app/zentaopro/config/`;
`chmod -R a+rx $basePath/app/zentaopro/bin/*`;
}
if(is_dir("$basePath/app/zentaoep/"))
{
`chmod -R 777 $basePath/app/zentaoep/tmp`;
`chmod -R 777 $basePath/app/zentaoep/www/data`;
`chmod 777 $basePath/app/zentaoep/www/`;
`chmod 777 $basePath/app/zentaoep/config/`;
`chmod -R a+rx $basePath/app/zentaoep/bin/*`;
}
/* Process argv. */
$params = array();
foreach($flipArgv as $key => $val)
{
if(strpos($key, '-') !== 0) continue;
if($key == '--aport') $key = '-ap';
if($key == '--mport') $key = '-mp';
if(isset($argv[$val + 1]) and is_numeric($argv[$val + 1]))
{
$params[$key] = $argv[$val + 1];
unset($argv[$val]);
unset($argv[$val + 1]);
}
}
if(isset($params['-ap'])) changePort($basePath . '/etc/apache/httpd.conf', $params['-ap'], array('^Listen +([0-9]+)', '<VirtualHost +.*:([0-9]+)>'));
if(isset($params['-mp']))
{
changePort($basePath . '/etc/mysql/my.cnf', $params['-mp'], '^port *= *([0-9]+)');
changePort($basePath . '/app/htdocs/index.php', $params['-mp'], 'localhost\:([0-9]+)\&');
$myReg = '^\$config->db->port *= *.([0-9]+)..*;';
if(file_exists("$basePath/app/zentao/config/my.php"))
{
`chmod 777 $basePath/app/zentao/config/my.php`;
$myFile = "$basePath/app/zentao/config/my.php";
changePort($myFile, $params['-mp'], $myReg);
}
if(file_exists("$basePath/app/zentaopro/config/my.php"))
{
`chmod 777 $basePath/app/zentaopro/config/my.php`;
$myFile = "$basePath/app/zentaopro/config/my.php";
changePort($myFile, $params['-mp'], $myReg);
}
if(file_exists("$basePath/app/zentaoep/config/my.php"))
{
`chmod 777 $basePath/app/zentaoep/config/my.php`;
$myFile = "$basePath/app/zentaoep/config/my.php";
changePort($myFile, $params['-mp'], $myReg);
}
}
if(!empty($argv)) $params['-k'] = reset($argv);
if(isset($params['-k']))
{
if(strpos(file_get_contents('/etc/group'), 'nogroup') === false) echo `groupadd nogroup`;
if(strpos(file_get_contents('/etc/passwd'), 'nobody') === false) echo `useradd nobody`;
`chmod -R 777 $basePath/tmp`;
`chmod -R 777 $basePath/logs`;
`chown -R nobody $basePath/data/mysql`;
switch($params['-k'])
{
case 'start':
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
if($httpd)
{
echo "Apache is running\n";
}
else
{
echo `$basePath/run/apache/apachectl start`;
sleep(2);
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
echo empty($httpd) ? "Start Apache fail. You can see the log /opt/zbox/logs/apache_error.log\n" : "Start Apache success\n";
}
break;
case 'stop':
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
if($httpd)
{
echo `$basePath/run/apache/apachectl stop`;
sleep(2);
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
echo empty($httpd) ? "Stop Apache success\n" : "Stop Apache fail. You can see the log /opt/zbox/logs/apache_error.log\n";
}
else
{
echo "Apache is not running\n";
}
break;
case 'restart':
echo `$basePath/run/apache/apachectl restart`;
sleep(2);
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
echo empty($httpd) ? "Restart Apache fail. You can see the log /opt/zbox/logs/apache_error.log\n" : "Restart Apache success\n";
break;
case 'status':
$httpd = `ps aux|grep '\/opt\/zbox\/run\/apache\/httpd '`;
echo empty($httpd) ? "Apache is not running\n" : "Apache is running\n";
}
}
function changePort($file, $port, $regs)
{
if(!is_array($regs)) $regs = array($regs);
$lines = file($file);
foreach($lines as $i => $line)
{
foreach($regs as $reg)
{
if(preg_match("/$reg/", $line, $matches)) $lines[$i] = str_replace($matches[1], $port, $line);
}
}
file_put_contents($file, join($lines));
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
修改连接MySQL的配置,重新启动禅道服务即可。服务能够正常使用的话,可以把/zbox
目录里所有跟MySQL相关的文件删掉。
$ vim /opt/zbox/app/zentao/config/my.php
将里面的数据库连接信息换成你自己的
$ /opt/zbox/zbox start
2
3
# 1.2.3 调整登录首页
不需要什么专业版、企业版、数据库管理功能,可以通过去掉禅道访问地址中的zentao路径,使其自动选择开源版的登录首页。
Step1:修改Apache配置
/opt/zbox/etc/apache/httpd.conf
// 修改前:
# If you want visit zentao like http://localhost/, uncomment these lines.
#<VirtualHost *:80>
# ServerAdmin [email protected]
# DocumentRoot "/opt/zbox/app/zentao/www"
# ServerName localhost
# <Directory />
# AllowOverride all
# Require all granted
# </Directory>
# ErrorLog "/opt/zbox/logs/apache_error.log"
# CustomLog "/opt/zbox/logs/apache_access.log" combind
#</VirtualHost>
// 修改后:
# If you want visit zentao like http://localhost/, uncomment these lines.
<VirtualHost *:80>
ServerAdmin zentao@local.net
DocumentRoot "/opt/zbox/app/zentao/www"
ServerName localhost
<Directory />
AllowOverride all
Require all granted
</Directory>
ErrorLog "/opt/zbox/logs/apache_error.log"
CustomLog "/opt/zbox/logs/apache_access.log" combind
</VirtualHost>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
重启服务
$ /opt/zbox/zbox restart
Step2:修改配置文件
/opt/zbox/app/zentao/config/my.php
// 修改前
$config->webRoot = getWebRoot();
// 修改后
$config->webRoot = '/';
2
3
4
/opt/zbox/app/zentao/www/.ztaccess
// 修改前
RewriteRule (.*)$ /zentao/index.php/$1 [L]
// 修改后
RewriteRule (.*)$ /index.php/$1 [L]
2
3
4
# 1.3 基本使用
# 1.3.1 配置用户及权限
[1] 配置角色权限
后台——人员管理——权限——按照自己单位的组织架构调整分组
对每个分组配置页面权限。
对每个分组配置功能权限。
[2] 批量添加用户
后台——人员管理—用户——“添加用户”按钮旁边的下拉选项里有“批量添加用户”。
# 1.3.2 最简使用指南
禅道的定位不是那种简单的任务管理软件,而是专业的协同管理软件。研发类的项目管理本身具有其复杂性,所以禅道提供的都是必备的功能。但这并不意味必须按照禅道的流程来使用,完全可以按照自己的实际情况来使用禅道。这里我们只用到它来管理产品提出的项目需求以及测试提出的功能bug。
[1] 创建项目集
点右上角的加号——项目集——填写表单并保存
[2] 创建项目及产品
点右上角的加号——项目——项目管理方式选择“Scrum”(敏捷开发)——填写表单并保存(可以在这里直接把产品也创建了)
[3] 设置团队
添加完项目和产品之后,会停留在项目列表页,点击该项目的“团队成员”按钮,再点击团队管理按钮,在这里配置团队成员。
[4] 需求管理
点右上角的加号——研发需求——填写表单并保存(可以在这里把功能模块也添加上)
注:这里可以直接把评审者设置成自己,评审通过后指派人员进行开发。
[5] bug管理
点右上角的加号——Bug——填写表单并保存
注:提出bug之后,由被指派人对bug进行修复或二次指派,修复问题后修改状态为已修复(尽量描述下是如何修复的),然后指派给测试人员或bug提出人,复测通过后将该bug关闭。
# 2. 原型设计工具
# 2.1 商业原型设计工具
以下是一些非常知名的项目原型设计工具。各自都有各自的特点和优势,适用的场景也不尽相同。
- MasterGo (opens new window):一款非常简洁、高效的原型设计工具,特别适合新手使用。它提供了丰富的组件库和模板,设计者可以方便地拖拽生成原型。
- 墨刀 (opens new window):一款国内非常知名的在线协作原型设计工具,有良好的团队协作能力。它支持实时协作,方便团队成员之间的沟通和协作。
- Figma (opens new window):一款国际知名的在线协作设计工具,同时支持原型设计和UI设计。其强大的协作能力、丰富的组件库和插件系统,使其成为许多设计团队的首选。
- 蓝湖 (opens new window):一款集设计、原型、项目管理为一体的设计平台。它有丰富的组件库和模板,同时也有良好的团队协作能力。
- Axure (opens new window):一款非常专业的原型设计工具,支持高度自定义和动态交互设计。其强大的功能和复杂性使其更适合有经验的设计者。
根据你的需求和经验,可以选择最适合你的设计工具。
- 如果你是新手,可能会更喜欢MasterGo或墨刀。
- 如果你是在团队中工作,并且需要实时协作,可能会更喜欢墨刀或Figma。
- 如果你是一名经验丰富的设计者,并且需要高度自定义的设计,那么Axure可能会是你的首选。
# 2.2 Penpot原型设计工具
# 2.2.1 Penpot简介
Penpot 是一款专为跨职能团队量身定制的开源设计软件,与行业领先的 Figma 齐名,提供了一个强大而灵活的在线设计解决方案。 其最大的亮点在于,用户不仅可以免费享用其云端服务,还能通过 Docker 轻松实现私有化部署,确保数据安全与自主控制。
- 项目地址:https://github.com/penpot/penpot (opens new window)
- 官网地址:https://penpot.app (opens new window)
- 官方版本试用:https://design.penpot.app (opens new window)
# 2.2.2 Penpot搭建
Step1:下载 docker-compose.yaml 文件
$ mkdir penpot && cd penpot
$ wget https://raw.githubusercontent.com/penpot/penpot/main/docker/images/docker-compose.yaml
2
Step2:修改 docker-compose.yaml 配置
除了看下端口占用情况之外,还需要修改3处地方才可以使用,不修改也能部署起来,但由于账号需要自行注册,登录那里根本过不去。
第1处:在209-216行左右,填写PENPOT_SMTP相关配置,下面是以163邮箱为例。需要注意的是 PENPOT_SMTP_PASSWORD 不是邮箱登录密码,而是邮箱授权码,这个要从邮件运营商那里获取,如何获取自行Google。
## Example SMTP/Email configuration. By default, emails are sent to the mailcatch
## service, but for production usage is recommended to setup a real SMTP
## provider. Emails are used to confirm user registrations & invitations. Look below
## how mailcatch service is configured.
## - [email protected]
## - [email protected]
## - PENPOT_SMTP_HOST=penpot-mailcatch
## - PENPOT_SMTP_PORT=1025
## - PENPOT_SMTP_USERNAME=
## - PENPOT_SMTP_PASSWORD=
## - PENPOT_SMTP_TLS=false
## - PENPOT_SMTP_SSL=false
- [email protected]
- [email protected]
- PENPOT_SMTP_HOST=smtp.163.com
- PENPOT_SMTP_PORT=465
- [email protected]
- PENPOT_SMTP_PASSWORD=xxxxxx
- PENPOT_SMTP_TLS=true
- PENPOT_SMTP_SSL=true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
第2处:在168行左右,将PENPOT_PUBLIC_URI的IP改为公网IP,不要用原来的localhost,不然邮箱验证链接给的是localhost打不开。
## - PENPOT_PUBLIC_URI=http://localhost:9001
- PENPOT_PUBLIC_URI=http://xxx.xxx.xxx.xxx:9001
2
第3处:在140行左右,或者搜索PENPOT_FLAGS即可,在后面加上disable-secure-session-cookies,不然需要 HTTPS 才可以访问。
## - PENPOT_FLAGS=enable-registration enable-login-with-password disable-email-verification enable-smtp enable-prepl-server
- PENPOT_FLAGS=enable-registration enable-login-with-password enable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies
2
Step3:启动Docker容器
$ docker compose -p penpot -f docker-compose.yaml up -d // 启动
$ docker compose -p penpot -f docker-compose.yaml down // 停止
2
Step4:访问页面并注册账号
Chrome浏览器打开 http:ip:9001
地址访问,看到页面之后还需要等一段时间才可以使用(后台还没起来时,点登录注册会出现“发生了某种错误”的报错),之后注册账号并登录即可(注册过程会往邮箱里发验证邮件,其它信息可以随便填)。
# 3. 文档管理工具
# 3.1 ShowDoc文档工具
# 3.1.1 ShowDoc简介
ShowDoc是一个适合IT团队的在线API文档、技术文档工具。可以方便地使用Markdown语法来编写API文档、数据字典文档、技术文档等。除此之外,还可以利用ShowDoc的自动化能力,从程序注释中自动生成API文档,或者从搭配的RunApi客户端中一边调试接口、一边自动生成文档。通过分配项目成员和团队成员,可以很方便地进行项目文档的权限管理和团队协作,也可以分享文档出去给朋友查看。
- 项目地址:https://github.com/star7th/showdoc (opens new window)
- 官方文档:https://www.showdoc.com.cn/help?page_id=1385767280275683 (opens new window)
- 在线体验:https://www.showdoc.com.cn (opens new window)
# 3.1.2 ShowDoc部署
Step1:从官网下载ShowDoc的服务器端部署脚本 showdoc (opens new window),将其上传到root目录并赋予700权限。
注:我们可以根据自己的需要对该一键部署脚本进行自定义修改,也可提取有效命令自行手动安装,后续的使用及配置以原始脚本为例。
Step2:输入命令安装ShowDoc,成功则如下图所示:
$ ./showdoc # 默认安装中文版。如果想安装英文版,请加上en参数,如 ./showdoc en
安装好后,ShowDoc的数据都会存放在 /showdoc_data/html
目录下。
附:其他管理ShowDoc的命令
$ ./showdoc stop #停止
$ ./showdoc restart #重启
$ ./showdoc update #升级showdoc到最新版
$ ./showdoc uninstall #卸载showdoc
2
3
4
设置开机自启:
$ docker update showdoc --restart=always
# 3.1.3 ShowDoc使用
可以打开 http://IP:4999
来访问showdoc,账户密码是showdoc/123456
,登录后便可以看到右上方的管理后台,建议修改管理员密码,功能界面如下:
注:可在使用Markdown编辑文档时在开头加一个[TOC]
,自动生成目录。
# 3.2 MinDoc文档工具
# 3.2.1 MinDoc简介
MinDoc 是一款针对IT团队开发的简单好用的文档管理系统。 可以用来储存日常接口文档,数据库字典,手册说明等文档。 内置项目管理,用户管理,权限管理等功能,能够满足大部分中小团队的文档管理需求。
- 项目地址:https://github.com/mindoc-org/mindoc (opens new window)
- 官方文档:https://doc.gsw945.com/docs/mindoc-docs (opens new window)
# 3.2.2 MinDoc部署
我这里使用MySQL去做数据持久化,首先创建一个数据库。
$ CREATE DATABASE mindoc DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;
MinDoc的官方Docker镜像已经挂掉了,可以使用源码和Dockerfile自己去构建镜像。
$ git clone https://github.com/mindoc-org/mindoc.git
$ cd mindoc
$ docker build -t mindoc_image .
$ docker run -itd --name mindoc \
-p 8181:8181 \
-e DB_ADAPTER=mysql \
-e MYSQL_PORT_3306_TCP_ADDR=111.111.111.111 \
-e MYSQL_PORT_3306_TCP_PORT=3306 \
-e MYSQL_INSTANCE_NAME=mindoc \
-e MYSQL_USERNAME=root \
-e MYSQL_PASSWORD=your_mysql_password \
mindoc_image
$ docker update mindoc --restart=always
2
3
4
5
6
7
8
9
10
11
12
13
# 3.2.3 MinDoc使用
可以打开 http://IP:8181
来访问MinDoc,账户密码是admin/123456
,功能界面如下:
# 4. 参考资料
[1] CentOS 8 部署禅道,并使用自己的数据库 from CSDN (opens new window)
[2] linux一键安装包去掉禅道访问地址中的zentao from 禅道官方文档 (opens new window)
[3] linux用一键安装包安装禅道 from 禅道官方文档 (opens new window)
[4] ShowDoc自动脚本安装 from showdoc官方文档 (opens new window)