feat(vmis): 租戶自動開通完整流程 + Admin Portal SSO + NC 行事曆訂閱
Backend: - schedule_tenant: NC 新容器自動 pgsql 安裝 (_nc_db_check 全新容器處理) - schedule_tenant: NC 初始化加入 Redis + APCu memcache 設定 (修正 OIDC invalid_state) - schedule_tenant: 新租戶 KC realm 自動設定 accessCodeLifespan=600s (修正 authentication_expired) - schedule_account: NC Mail 帳號自動設定 (nc_mail_result/nc_mail_done_at) - schedule_account: NC 台灣國定假日行事曆自動訂閱 (CalDAV MKCALENDAR) - nextcloud_client: 新增 subscribe_calendar() CalDAV 訂閱方法 - settings: 新增系統設定 API (site_title/version/timezone/SSO/Keycloak) - models/result: 新增 nc_mail_result, nc_mail_done_at 欄位 - alembic: 遷移 002(system_settings) 003(keycloak_admin) 004(nc_mail_result) Frontend (Admin Portal): - 新增完整管理後台 (index/tenants/accounts/servers/schedules/logs/settings/system-status) - api.js: Keycloak JS Adapter SSO 整合 (PKCE/S256, fallback KC JS 來源, 自動 token 更新) - index.html: Promise.allSettled 取代 Promise.all,防止單一 API 失敗影響整頁 - 所有頁面加入 try/catch + toast 錯誤處理 - 新增品牌 LOGO 與 favicon Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
249
docker/radicale/README.md
Normal file
249
docker/radicale/README.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# Radicale CalDAV/CardDAV Server
|
||||
|
||||
Virtual MIS 日曆與聯絡人服務後端。
|
||||
|
||||
## 服務資訊
|
||||
|
||||
- **服務名稱**: Radicale CalDAV/CardDAV Server
|
||||
- **容器名稱**: vmis-radicale
|
||||
- **內部埠號**: 5232
|
||||
- **外部埠號**: 5232 (開發環境)
|
||||
- **認證方式**: HTTP Header (X-Remote-User) - 由 Keycloak OAuth2 整合
|
||||
- **資料儲存**: File System (/data/collections)
|
||||
|
||||
## 功能
|
||||
|
||||
- ✅ CalDAV - 日曆同步 (RFC 4791)
|
||||
- ✅ CardDAV - 聯絡人同步 (RFC 6352)
|
||||
- ✅ HTTP Header 認證
|
||||
- ✅ 多使用者支援
|
||||
- ✅ Web 管理介面
|
||||
|
||||
## 目錄結構
|
||||
|
||||
```
|
||||
radicale/
|
||||
├── config/
|
||||
│ └── config # Radicale 配置檔
|
||||
├── data/ # 資料目錄(自動建立)
|
||||
│ └── collections/ # 日曆與聯絡人資料
|
||||
├── docker-compose.yml # Docker Compose 配置
|
||||
└── README.md # 本文件
|
||||
```
|
||||
|
||||
## 部署步驟
|
||||
|
||||
### 1. 建立資料目錄
|
||||
|
||||
```bash
|
||||
mkdir -p data/collections
|
||||
```
|
||||
|
||||
### 2. 設定權限
|
||||
|
||||
```bash
|
||||
# 確保資料目錄權限正確(UID=1000, GID=1000)
|
||||
sudo chown -R 1000:1000 data/
|
||||
chmod -R 750 data/
|
||||
```
|
||||
|
||||
### 3. 啟動服務
|
||||
|
||||
```bash
|
||||
# 啟動
|
||||
docker-compose up -d
|
||||
|
||||
# 查看日誌
|
||||
docker-compose logs -f
|
||||
|
||||
# 停止
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### 4. 驗證服務
|
||||
|
||||
```bash
|
||||
# 檢查服務狀態
|
||||
docker-compose ps
|
||||
|
||||
# 測試連線
|
||||
curl -I http://localhost:5232
|
||||
|
||||
# 預期回應: HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
## 整合架構
|
||||
|
||||
### Virtual MIS 整合
|
||||
|
||||
```
|
||||
Virtual MIS Backend
|
||||
↓ caldav_service.py
|
||||
Radicale (CalDAV/CardDAV)
|
||||
↓ File System
|
||||
/data/collections/
|
||||
├── {username}/
|
||||
│ ├── {calendar-uuid}/ # 日曆
|
||||
│ └── {addressbook-uuid}/ # 通訊錄
|
||||
```
|
||||
|
||||
### 認證流程
|
||||
|
||||
```
|
||||
1. 使用者登入 Keycloak SSO
|
||||
2. Virtual MIS Backend 取得 username
|
||||
3. Backend 使用 X-Remote-User Header 呼叫 Radicale
|
||||
4. Radicale 信任 Header,直接存取對應使用者資料
|
||||
```
|
||||
|
||||
## 資料結構
|
||||
|
||||
### 日曆資料 (CalDAV)
|
||||
|
||||
```
|
||||
/data/collections/{username}/{calendar-uuid}/
|
||||
├── event-1.ics
|
||||
├── event-2.ics
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 聯絡人資料 (CardDAV)
|
||||
|
||||
```
|
||||
/data/collections/{username}/{addressbook-uuid}/
|
||||
├── contact-1.vcf
|
||||
├── contact-2.vcf
|
||||
└── ...
|
||||
```
|
||||
|
||||
## 客戶端配置
|
||||
|
||||
### iOS / macOS
|
||||
|
||||
**日曆 (CalDAV)**:
|
||||
```
|
||||
伺服器: 10.1.0.254:5232 (開發環境)
|
||||
使用者名稱: {Keycloak username}
|
||||
密碼: (由 Backend 處理)
|
||||
使用 SSL: 否 (開發環境) / 是 (正式環境)
|
||||
```
|
||||
|
||||
**聯絡人 (CardDAV)**:
|
||||
```
|
||||
伺服器: 10.1.0.254:5232
|
||||
使用者名稱: {Keycloak username}
|
||||
密碼: (由 Backend 處理)
|
||||
使用 SSL: 否 (開發環境) / 是 (正式環境)
|
||||
```
|
||||
|
||||
### Android (DAVx⁵)
|
||||
|
||||
```
|
||||
基礎 URL: http://10.1.0.254:5232/
|
||||
使用者名稱: {Keycloak username}
|
||||
密碼: (由 Backend 處理)
|
||||
```
|
||||
|
||||
### Thunderbird
|
||||
|
||||
**日曆**:
|
||||
```
|
||||
位置: http://10.1.0.254:5232/{username}/{calendar-uuid}/
|
||||
```
|
||||
|
||||
**聯絡人** (需要 CardBook 擴充套件):
|
||||
```
|
||||
URL: http://10.1.0.254:5232/{username}/{addressbook-uuid}/
|
||||
```
|
||||
|
||||
## 監控與維護
|
||||
|
||||
### 查看日誌
|
||||
|
||||
```bash
|
||||
# 即時日誌
|
||||
docker-compose logs -f radicale
|
||||
|
||||
# 最近 100 行
|
||||
docker-compose logs --tail=100 radicale
|
||||
```
|
||||
|
||||
### 備份策略
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 備份腳本
|
||||
BACKUP_DIR="/backups/radicale"
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
# 備份資料
|
||||
tar -czf ${BACKUP_DIR}/radicale_data_${DATE}.tar.gz \
|
||||
./data/
|
||||
|
||||
# 保留最近 30 天
|
||||
find ${BACKUP_DIR} -name "radicale_data_*.tar.gz" -mtime +30 -delete
|
||||
```
|
||||
|
||||
### 效能監控
|
||||
|
||||
```bash
|
||||
# 查看儲存空間
|
||||
du -sh data/
|
||||
|
||||
# 查看容器資源使用
|
||||
docker stats vmis-radicale
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 問題 1: 無法連線
|
||||
|
||||
**檢查**:
|
||||
```bash
|
||||
# 檢查容器狀態
|
||||
docker-compose ps
|
||||
|
||||
# 檢查埠號占用
|
||||
netstat -tulpn | grep 5232
|
||||
|
||||
# 檢查防火牆
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
### 問題 2: 認證失敗
|
||||
|
||||
**檢查**:
|
||||
- X-Remote-User Header 是否正確傳遞
|
||||
- Radicale 配置檔中 auth.type 是否為 http_x_remote_user
|
||||
- Backend 呼叫時是否正確設定 Header
|
||||
|
||||
### 問題 3: 資料無法寫入
|
||||
|
||||
**檢查**:
|
||||
```bash
|
||||
# 檢查目錄權限
|
||||
ls -la data/
|
||||
|
||||
# 修正權限
|
||||
sudo chown -R 1000:1000 data/
|
||||
chmod -R 750 data/
|
||||
```
|
||||
|
||||
## 安全建議
|
||||
|
||||
1. **認證**: 使用 Keycloak SSO 統一認證
|
||||
2. **網路隔離**: 僅允許 Backend 存取 Radicale
|
||||
3. **HTTPS**: 正式環境必須使用 HTTPS
|
||||
4. **備份**: 定期備份 data/ 目錄
|
||||
5. **權限**: 嚴格控制檔案系統權限
|
||||
|
||||
## 參考文件
|
||||
|
||||
- [Radicale 官方文件](https://radicale.org/v3.html)
|
||||
- [CalDAV 協議 (RFC 4791)](https://tools.ietf.org/html/rfc4791)
|
||||
- [CardDAV 協議 (RFC 6352)](https://tools.ietf.org/html/rfc6352)
|
||||
|
||||
## 更新記錄
|
||||
|
||||
- **2026-03-02**: 建立 Radicale Docker Compose 配置
|
||||
- **2026-03-02**: 整合 Virtual MIS Calendar & Contacts
|
||||
34
docker/radicale/config/config
Normal file
34
docker/radicale/config/config
Normal file
@@ -0,0 +1,34 @@
|
||||
[server]
|
||||
# 監聽所有介面
|
||||
hosts = 0.0.0.0:5232
|
||||
|
||||
# 最大連線數
|
||||
max_connections = 100
|
||||
|
||||
# 逾時設定
|
||||
timeout = 60
|
||||
|
||||
[auth]
|
||||
# 使用 HTTP Header 認證 (由 Keycloak OAuth2 Proxy 提供)
|
||||
type = http_x_remote_user
|
||||
|
||||
[storage]
|
||||
# 檔案系統儲存
|
||||
type = multifilesystem
|
||||
|
||||
# 資料目錄
|
||||
filesystem_folder = /data/collections
|
||||
|
||||
# Hook for changes (optional - for git versioning)
|
||||
# hook = git add -A && git commit -m "Changes by %(user)s"
|
||||
|
||||
[web]
|
||||
# 啟用 Web 介面
|
||||
type = internal
|
||||
|
||||
[logging]
|
||||
# 日誌等級
|
||||
level = info
|
||||
|
||||
# 日誌格式
|
||||
# debug 模式可設為 debug
|
||||
44
docker/radicale/docker-compose.yml
Normal file
44
docker/radicale/docker-compose.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
radicale:
|
||||
image: tomsquest/docker-radicale:latest
|
||||
container_name: vmis-radicale
|
||||
restart: unless-stopped
|
||||
|
||||
# 環境變數
|
||||
environment:
|
||||
# 設定時區
|
||||
- TZ=Asia/Taipei
|
||||
|
||||
# UID/GID (與 porsche 使用者相同)
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
|
||||
# 資料卷
|
||||
volumes:
|
||||
# 配置檔
|
||||
- ./config:/config:ro
|
||||
|
||||
# 資料目錄
|
||||
- ./data:/data
|
||||
|
||||
# 埠號
|
||||
ports:
|
||||
- "5232:5232"
|
||||
|
||||
# 網路
|
||||
networks:
|
||||
- vmis-network
|
||||
|
||||
# 健康檢查
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5232/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
vmis-network:
|
||||
external: true
|
||||
Reference in New Issue
Block a user