917ab7ccf1
Add early termination visit workflow with ordering, non-applicable visit handling, visit window display, and medication adherence support. Extend monitoring visit issue template fields, site scoping, setup draft project info handling, login security UI, attachment behavior, and related tests/migrations.
566 lines
9.5 KiB
Markdown
566 lines
9.5 KiB
Markdown
# CTMS 安装步骤向导
|
||
|
||
按目标分支选择对应章节执行:
|
||
|
||
- [dev 分支安装](#dev-分支安装)
|
||
- [main 分支安装](#main-分支安装)
|
||
- [release 分支安装](#release-分支安装)
|
||
|
||
## 安装前准备
|
||
|
||
三个分支都先完成本节。
|
||
|
||
### 1. 准备安装目录
|
||
|
||
```bash
|
||
mkdir -p /opt/ctms
|
||
cd /opt/ctms
|
||
```
|
||
|
||
### 2. 安装 Docker
|
||
|
||
Linux 可使用 Docker Engine 或 Docker Desktop。安装完成后确认 Docker Compose v2 可用:
|
||
|
||
```bash
|
||
docker --version
|
||
docker compose version
|
||
```
|
||
|
||
如果当前用户不能执行 Docker 命令,将用户加入 `docker` 组后重新登录:
|
||
|
||
```bash
|
||
sudo usermod -aG docker "$USER"
|
||
```
|
||
|
||
macOS 安装 Docker Desktop 后执行:
|
||
|
||
```bash
|
||
docker --version
|
||
docker compose version
|
||
```
|
||
|
||
### 3. 安装基础工具
|
||
|
||
Linux:
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install -y git openssl curl lsof
|
||
```
|
||
|
||
macOS:
|
||
|
||
```bash
|
||
brew install git openssl curl
|
||
```
|
||
|
||
### 4. 检查端口
|
||
|
||
```bash
|
||
lsof -nP -iTCP:8888 -sTCP:LISTEN
|
||
lsof -nP -iTCP:8000 -sTCP:LISTEN
|
||
lsof -nP -iTCP:5432 -sTCP:LISTEN
|
||
```
|
||
|
||
如果命令有输出,先停止占用这些端口的服务,或调整 `docker-compose.yaml` 中的端口映射。
|
||
|
||
### 5. 拉取代码
|
||
|
||
首次安装:
|
||
|
||
```bash
|
||
git clone https://github.com/chengchengzhou7/CTMS.git
|
||
cd CTMS
|
||
```
|
||
|
||
已有仓库:
|
||
|
||
```bash
|
||
cd /opt/ctms/CTMS
|
||
git fetch --prune origin
|
||
```
|
||
|
||
### 6. 确认本地配置不会提交
|
||
|
||
```bash
|
||
grep -n "^\\.env$" .gitignore
|
||
grep -n "^\\.env\\.\\*$" .gitignore
|
||
```
|
||
|
||
预期能看到 `.env` 和 `.env.*` 已被忽略。
|
||
|
||
## dev 分支安装
|
||
|
||
### 1. 切换分支
|
||
|
||
```bash
|
||
git checkout dev
|
||
git pull --rebase origin dev
|
||
```
|
||
|
||
### 2. 写入环境配置
|
||
|
||
在仓库根目录创建或覆盖 `.env`:
|
||
|
||
```bash
|
||
cat > .env <<'EOF'
|
||
COMPOSE_PROJECT_NAME=ctms_dev
|
||
ENV=development
|
||
JWT_SECRET_KEY=dev-secret
|
||
LOGIN_RSA_KEY_ID=default
|
||
LOGIN_RSA_PRIVATE_KEY=
|
||
EOF
|
||
```
|
||
|
||
### 3. 构建镜像并启动
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
### 4. 检查容器状态
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
确认 `ctms_db`、`ctms_backend`、`ctms_nginx` 都是 `Up`,且 `ctms_db` 为 `healthy`。
|
||
|
||
### 5. 检查后端环境
|
||
|
||
```bash
|
||
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY)))"
|
||
```
|
||
|
||
预期输出:
|
||
|
||
```text
|
||
ENV=development
|
||
JWT_SECRET_IS_DEV=True
|
||
LOGIN_RSA_PRIVATE_KEY_SET=False
|
||
```
|
||
|
||
### 6. 检查接口
|
||
|
||
```bash
|
||
curl -i http://127.0.0.1:8888/health
|
||
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
|
||
```
|
||
|
||
两个接口都应返回 `HTTP/1.1 200 OK`。
|
||
|
||
### 7. 打开系统
|
||
|
||
```text
|
||
http://localhost:8888
|
||
```
|
||
|
||
### 8. 运行验证
|
||
|
||
后端:
|
||
|
||
```bash
|
||
docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest
|
||
```
|
||
|
||
前端:
|
||
|
||
```bash
|
||
cd frontend
|
||
npm install
|
||
npm run test:unit
|
||
npm run type-check
|
||
npm run build
|
||
cd ..
|
||
```
|
||
|
||
## main 分支安装
|
||
|
||
### 1. 切换分支
|
||
|
||
```bash
|
||
git checkout main
|
||
git pull --rebase origin main
|
||
```
|
||
|
||
### 2. 生成密钥
|
||
|
||
生成 JWT 密钥:
|
||
|
||
```bash
|
||
openssl rand -hex 32
|
||
```
|
||
|
||
生成 RSA 私钥文件:
|
||
|
||
```bash
|
||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_main.pem
|
||
```
|
||
|
||
生成可写入 `.env` 的 RSA 私钥单行文本:
|
||
|
||
```bash
|
||
awk '{printf "%s\\n", $0}' login_rsa_main.pem
|
||
```
|
||
|
||
### 3. 写入环境配置
|
||
|
||
在仓库根目录创建或覆盖 `.env`,将占位符替换为上一步生成的值:
|
||
|
||
```bash
|
||
cat > .env <<'EOF'
|
||
COMPOSE_PROJECT_NAME=ctms_main
|
||
ENV=production
|
||
JWT_SECRET_KEY=<替换为 JWT 密钥>
|
||
LOGIN_RSA_KEY_ID=main-YYYYMMDD
|
||
LOGIN_RSA_PRIVATE_KEY=<替换为 RSA 私钥单行文本>
|
||
EOF
|
||
```
|
||
|
||
### 4. 检查 Compose 配置
|
||
|
||
```bash
|
||
docker compose config
|
||
```
|
||
|
||
确认输出中包含:
|
||
|
||
```text
|
||
ENV: production
|
||
LOGIN_RSA_KEY_ID: main-YYYYMMDD
|
||
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'
|
||
```
|
||
|
||
### 5. 初始化数据库
|
||
|
||
```bash
|
||
docker compose run --rm backend-init
|
||
```
|
||
|
||
### 6. 构建镜像并启动
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
### 7. 检查容器状态
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
确认 `ctms_db`、`ctms_backend`、`ctms_nginx` 都是 `Up`,且 `ctms_db` 为 `healthy`。
|
||
|
||
### 8. 检查后端环境
|
||
|
||
```bash
|
||
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY))); print('LOGIN_RSA_KEY_ID=' + settings.LOGIN_RSA_KEY_ID)"
|
||
```
|
||
|
||
预期输出:
|
||
|
||
```text
|
||
ENV=production
|
||
JWT_SECRET_IS_DEV=False
|
||
LOGIN_RSA_PRIVATE_KEY_SET=True
|
||
LOGIN_RSA_KEY_ID=main-YYYYMMDD
|
||
```
|
||
|
||
### 9. 检查接口
|
||
|
||
本机:
|
||
|
||
```bash
|
||
curl -i http://127.0.0.1:8888/health
|
||
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
|
||
```
|
||
|
||
远程域名:
|
||
|
||
```bash
|
||
curl -i https://<main-domain>/health
|
||
curl -i https://<main-domain>/api/v1/auth/login-key
|
||
```
|
||
|
||
接口应返回 `HTTP/1.1 200 OK`。
|
||
|
||
### 10. 打开系统
|
||
|
||
本机:
|
||
|
||
```text
|
||
http://localhost:8888
|
||
```
|
||
|
||
远程访问:
|
||
|
||
```text
|
||
https://<main-domain>
|
||
```
|
||
|
||
远程访问必须使用 HTTPS。
|
||
|
||
### 11. 运行验证
|
||
|
||
后端:
|
||
|
||
```bash
|
||
docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest
|
||
```
|
||
|
||
前端:
|
||
|
||
```bash
|
||
cd frontend
|
||
npm install
|
||
npm run test:unit
|
||
npm run type-check
|
||
npm run build
|
||
cd ..
|
||
```
|
||
|
||
## release 分支安装
|
||
|
||
### 1. 切换分支
|
||
|
||
```bash
|
||
git checkout release
|
||
git pull --rebase origin release
|
||
```
|
||
|
||
### 2. 准备 HTTPS 域名
|
||
|
||
正式访问地址必须是:
|
||
|
||
```text
|
||
https://<production-domain>
|
||
```
|
||
|
||
如果服务器前面有反向代理,确认代理规则:
|
||
|
||
```text
|
||
/ -> CTMS nginx 8888
|
||
/api/* -> CTMS nginx 8888
|
||
/health -> CTMS nginx 8888
|
||
```
|
||
|
||
### 3. 生成密钥
|
||
|
||
生成 JWT 密钥:
|
||
|
||
```bash
|
||
openssl rand -hex 32
|
||
```
|
||
|
||
生成 RSA 私钥文件:
|
||
|
||
```bash
|
||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out login_rsa_release.pem
|
||
```
|
||
|
||
生成可写入 `.env` 的 RSA 私钥单行文本:
|
||
|
||
```bash
|
||
awk '{printf "%s\\n", $0}' login_rsa_release.pem
|
||
```
|
||
|
||
将 `login_rsa_release.pem` 保存到服务器安全目录或密钥管理系统。
|
||
|
||
### 4. 写入环境配置
|
||
|
||
在仓库根目录创建或覆盖 `.env`,将占位符替换为生产值:
|
||
|
||
```bash
|
||
cat > .env <<'EOF'
|
||
COMPOSE_PROJECT_NAME=ctms_release
|
||
ENV=production
|
||
JWT_SECRET_KEY=<替换为生产 JWT 密钥>
|
||
LOGIN_RSA_KEY_ID=release-YYYYMMDD
|
||
LOGIN_RSA_PRIVATE_KEY=<替换为生产 RSA 私钥单行文本>
|
||
EOF
|
||
```
|
||
|
||
确认 `.env` 没有进入 Git 暂存区:
|
||
|
||
```bash
|
||
git status --short .env
|
||
```
|
||
|
||
预期无输出。
|
||
|
||
### 5. 检查 Compose 配置
|
||
|
||
```bash
|
||
docker compose config
|
||
```
|
||
|
||
确认输出中包含:
|
||
|
||
```text
|
||
ENV: production
|
||
JWT_SECRET_KEY: <不是 dev-secret>
|
||
LOGIN_RSA_KEY_ID: release-YYYYMMDD
|
||
LOGIN_RSA_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----...'
|
||
```
|
||
|
||
### 6. 初始化数据库
|
||
|
||
```bash
|
||
docker compose run --rm backend-init
|
||
```
|
||
|
||
确认命令成功后再启动服务。
|
||
|
||
### 7. 构建镜像并启动
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
### 8. 检查容器状态
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
确认 `ctms_db`、`ctms_backend`、`ctms_nginx` 都是 `Up`,且 `ctms_db` 为 `healthy`。
|
||
|
||
### 9. 检查后端环境
|
||
|
||
```bash
|
||
docker compose exec backend python -c "from app.core.config import settings; print('ENV=' + settings.ENV); print('JWT_SECRET_IS_DEV=' + str(settings.JWT_SECRET_KEY == 'dev-secret')); print('LOGIN_RSA_PRIVATE_KEY_SET=' + str(bool(settings.LOGIN_RSA_PRIVATE_KEY))); print('LOGIN_RSA_KEY_ID=' + settings.LOGIN_RSA_KEY_ID)"
|
||
```
|
||
|
||
预期输出:
|
||
|
||
```text
|
||
ENV=production
|
||
JWT_SECRET_IS_DEV=False
|
||
LOGIN_RSA_PRIVATE_KEY_SET=True
|
||
LOGIN_RSA_KEY_ID=release-YYYYMMDD
|
||
```
|
||
|
||
### 10. 检查生产接口
|
||
|
||
```bash
|
||
curl -i https://<production-domain>/health
|
||
curl -i https://<production-domain>/api/v1/auth/login-key
|
||
```
|
||
|
||
两个接口都应返回 `HTTP/1.1 200 OK`。
|
||
|
||
### 11. 打开系统并登录
|
||
|
||
```text
|
||
https://<production-domain>
|
||
```
|
||
|
||
初始化管理员:
|
||
|
||
```text
|
||
admin@huapont.cn / admin123
|
||
```
|
||
|
||
首次登录后立即修改初始密码。
|
||
|
||
### 12. 发布后检查
|
||
|
||
查看容器:
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
查看后端日志:
|
||
|
||
```bash
|
||
docker compose logs --tail=200 backend
|
||
```
|
||
|
||
查看 nginx 日志:
|
||
|
||
```bash
|
||
docker compose logs --tail=200 nginx
|
||
```
|
||
|
||
执行 smoke:
|
||
|
||
```bash
|
||
BASE_URL=https://<production-domain> EMAIL=<admin-email> PASSWORD=<admin-password> bash docs/setup-config-curl-smoke.sh
|
||
```
|
||
|
||
## 常见安装问题
|
||
|
||
### 端口被占用
|
||
|
||
检查:
|
||
|
||
```bash
|
||
lsof -nP -iTCP:8888 -sTCP:LISTEN
|
||
lsof -nP -iTCP:8000 -sTCP:LISTEN
|
||
lsof -nP -iTCP:5432 -sTCP:LISTEN
|
||
```
|
||
|
||
处理:停止占用进程,或调整 `docker-compose.yaml` 端口映射。
|
||
|
||
### 容器名冲突
|
||
|
||
检查:
|
||
|
||
```bash
|
||
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||
```
|
||
|
||
处理:
|
||
|
||
```bash
|
||
docker compose down
|
||
```
|
||
|
||
如果同一台机器要同时运行多套 CTMS,需为每套环境调整 `docker-compose.yaml` 中的 `container_name` 和端口。
|
||
|
||
### production 启动失败
|
||
|
||
检查:
|
||
|
||
```bash
|
||
grep -n "ENV\\|JWT_SECRET_KEY\\|LOGIN_RSA" .env
|
||
```
|
||
|
||
确认:
|
||
|
||
```text
|
||
ENV=production
|
||
JWT_SECRET_KEY 不是 dev-secret
|
||
LOGIN_RSA_PRIVATE_KEY 不是空值
|
||
LOGIN_RSA_PRIVATE_KEY 包含 -----BEGIN PRIVATE KEY-----
|
||
```
|
||
|
||
### 远程访问无法登录
|
||
|
||
检查当前浏览器地址。如果不是 `https://`,改用 HTTPS 域名访问:
|
||
|
||
```text
|
||
https://<domain>
|
||
```
|
||
|
||
本机 `dev` 可使用:
|
||
|
||
```text
|
||
http://localhost:8888
|
||
```
|
||
|
||
### 切换分支后环境不正确
|
||
|
||
重新执行对应分支的 `.env` 配置,然后重建:
|
||
|
||
```bash
|
||
docker compose up -d --build backend nginx
|
||
```
|
||
|
||
再检查:
|
||
|
||
```bash
|
||
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)"
|
||
```
|