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:
254
docs/WebMail_SSO_Integration_Guide.md
Normal file
254
docs/WebMail_SSO_Integration_Guide.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# WebMail Keycloak SSO 整合指南
|
||||
|
||||
本指南說明如何將 Roundcube WebMail 與 Keycloak SSO 整合。
|
||||
|
||||
## 前置條件
|
||||
|
||||
已完成:
|
||||
- ✅ Keycloak Client 已建立
|
||||
- ✅ Client ID: `webmail`
|
||||
- ✅ Client Secret: `CDUcB68SZUEZ2zmiQV4cz22czjw6Sn1q`
|
||||
- ✅ Realm: `vmis-admin`
|
||||
|
||||
## 步驟 1: 連接到 WebMail 主機
|
||||
|
||||
```bash
|
||||
ssh 10.1.0.254
|
||||
```
|
||||
|
||||
## 步驟 2: 查看 Roundcube 容器
|
||||
|
||||
```bash
|
||||
docker ps | grep -i roundcube
|
||||
```
|
||||
|
||||
記錄容器名稱 (例如: `roundcube` 或 `webmail`)
|
||||
|
||||
## 步驟 3: 查看 Roundcube 配置掛載路徑
|
||||
|
||||
```bash
|
||||
docker inspect <容器名稱> | grep -A 5 "Mounts"
|
||||
```
|
||||
|
||||
找出配置檔案的掛載路徑 (通常是 `/var/www/html/config` 或類似路徑)
|
||||
|
||||
## 步驟 4: 安裝 OAuth2 插件
|
||||
|
||||
### 方法 A: 如果 Roundcube 使用官方 Docker 映像
|
||||
|
||||
1. 進入容器:
|
||||
```bash
|
||||
docker exec -it <容器名稱> bash
|
||||
```
|
||||
|
||||
2. 使用 Composer 安裝 OAuth2 插件:
|
||||
```bash
|
||||
cd /var/www/html
|
||||
composer require roundcube/oauth2
|
||||
```
|
||||
|
||||
3. 啟用插件 (編輯 config/config.inc.php):
|
||||
```bash
|
||||
vi config/config.inc.php
|
||||
```
|
||||
|
||||
找到 `$config['plugins']` 行,加入 `'oauth2'`:
|
||||
```php
|
||||
$config['plugins'] = array(
|
||||
'oauth2',
|
||||
// ... 其他插件
|
||||
);
|
||||
```
|
||||
|
||||
### 方法 B: 如果無法使用 Composer
|
||||
|
||||
手動下載並安裝插件:
|
||||
|
||||
```bash
|
||||
cd /var/www/html/plugins
|
||||
git clone https://github.com/roundcube/roundcubemail-oauth2.git oauth2
|
||||
```
|
||||
|
||||
## 步驟 5: 配置 OAuth2 插件
|
||||
|
||||
建立或編輯 `config/oauth2.inc.php`:
|
||||
|
||||
```bash
|
||||
vi /var/www/html/config/oauth2.inc.php
|
||||
```
|
||||
|
||||
加入以下內容:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Roundcube OAuth2 Configuration
|
||||
* Keycloak SSO Integration for WebMail
|
||||
*/
|
||||
|
||||
$config['oauth2'] = array(
|
||||
'provider' => 'generic',
|
||||
'client_id' => 'webmail',
|
||||
'client_secret' => 'CDUcB68SZUEZ2zmiQV4cz22czjw6Sn1q',
|
||||
'auth_uri' => 'https://auth.lab.taipei/realms/vmis-admin/protocol/openid-connect/auth',
|
||||
'token_uri' => 'https://auth.lab.taipei/realms/vmis-admin/protocol/openid-connect/token',
|
||||
'identity_uri' => 'https://auth.lab.taipei/realms/vmis-admin/protocol/openid-connect/userinfo',
|
||||
'redirect_uri' => 'https://webmail.porscheworld.tw/index.php/login/oauth',
|
||||
'scope' => 'openid email profile',
|
||||
'login_redirect' => true,
|
||||
'username_field' => 'email',
|
||||
'identity_fields' => array(
|
||||
'email' => 'email',
|
||||
'name' => 'name',
|
||||
'username' => 'preferred_username'
|
||||
),
|
||||
);
|
||||
|
||||
// 自動登入 (可選)
|
||||
$config['oauth2_auto_login'] = true;
|
||||
|
||||
// 允許傳統登入 (開發階段建議保留)
|
||||
$config['oauth2_allow_traditional_login'] = true;
|
||||
```
|
||||
|
||||
## 步驟 6: 修改 Roundcube 主配置
|
||||
|
||||
編輯 `config/config.inc.php`:
|
||||
|
||||
```bash
|
||||
vi /var/www/html/config/config.inc.php
|
||||
```
|
||||
|
||||
確保以下設定:
|
||||
|
||||
```php
|
||||
// 啟用插件
|
||||
$config['plugins'] = array(
|
||||
'oauth2',
|
||||
// ... 其他插件
|
||||
);
|
||||
|
||||
// IMAP 設定 (根據實際郵件伺服器調整)
|
||||
$config['default_host'] = 'ssl://10.1.0.254';
|
||||
$config['default_port'] = 993;
|
||||
|
||||
// SMTP 設定
|
||||
$config['smtp_server'] = 'tls://10.1.0.254';
|
||||
$config['smtp_port'] = 587;
|
||||
|
||||
// 使用者名稱網域 (根據 Keycloak 使用者的 email 設定)
|
||||
$config['username_domain'] = array(
|
||||
'porscheworld.tw' => 'porscheworld.tw',
|
||||
'lab.taipei' => 'lab.taipei',
|
||||
'ease.taipei' => 'ease.taipei',
|
||||
);
|
||||
|
||||
// 自動完成郵件地址
|
||||
$config['mail_domain'] = 'lab.taipei';
|
||||
```
|
||||
|
||||
## 步驟 7: 設定郵件地址對應規則
|
||||
|
||||
Keycloak 使用者的 `email` 屬性應該對應到郵件伺服器的帳號。
|
||||
|
||||
### 確保 Keycloak 使用者有正確的 email
|
||||
|
||||
1. 登入 Keycloak Admin Console:
|
||||
```
|
||||
https://auth.lab.taipei/admin
|
||||
```
|
||||
|
||||
2. 進入 `vmis-admin` Realm
|
||||
|
||||
3. 檢查使用者的 Email 欄位,例如:
|
||||
- Username: `sysadmin`
|
||||
- Email: `admin@lab.taipei`
|
||||
|
||||
這個 Email 必須是郵件伺服器上實際存在的帳號。
|
||||
|
||||
## 步驟 8: 重啟 Roundcube 容器
|
||||
|
||||
```bash
|
||||
docker restart <容器名稱>
|
||||
```
|
||||
|
||||
## 步驟 9: 測試 SSO 登入
|
||||
|
||||
1. 清除瀏覽器 Cookie
|
||||
|
||||
2. 訪問 WebMail:
|
||||
```
|
||||
https://webmail.porscheworld.tw
|
||||
```
|
||||
|
||||
3. 應該會自動重導向到 Keycloak 登入頁面:
|
||||
```
|
||||
https://auth.lab.taipei/realms/vmis-admin/protocol/openid-connect/auth?...
|
||||
```
|
||||
|
||||
4. 使用 Keycloak 帳號登入 (例如: `sysadmin`)
|
||||
|
||||
5. 登入成功後,應該會重導向回 WebMail 並自動登入郵件帳號
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 問題 1: 無法重導向到 Keycloak
|
||||
|
||||
**檢查:**
|
||||
- OAuth2 插件是否正確安裝
|
||||
- `config/oauth2.inc.php` 是否存在且設定正確
|
||||
- Roundcube 容器日誌: `docker logs <容器名稱>`
|
||||
|
||||
### 問題 2: 登入後顯示「Invalid credentials」
|
||||
|
||||
**可能原因:**
|
||||
- Keycloak 使用者的 email 與郵件伺服器帳號不符
|
||||
- 郵件伺服器密碼與 Keycloak 密碼不同
|
||||
|
||||
**解決方案:**
|
||||
需要實作「密碼同步」或使用「IMAP OAuth2」:
|
||||
|
||||
1. **方案 A: 密碼同步** - Keycloak 密碼變更時同步到郵件伺服器
|
||||
2. **方案 B: IMAP OAuth2** - 郵件伺服器支援 OAuth2 認證 (需要 Docker Mailserver 配置)
|
||||
|
||||
### 問題 3: 重導向 URI 不符
|
||||
|
||||
**錯誤訊息:**
|
||||
```
|
||||
Invalid redirect_uri
|
||||
```
|
||||
|
||||
**解決方案:**
|
||||
檢查 Keycloak Client 的 Valid Redirect URIs 設定:
|
||||
```
|
||||
https://webmail.porscheworld.tw/*
|
||||
```
|
||||
|
||||
## 進階設定
|
||||
|
||||
### 整合 HR Portal 多帳號切換
|
||||
|
||||
如果要實現「員工可以使用 SSO 登入後,切換不同的郵件帳號」:
|
||||
|
||||
1. 安裝 `multi_accounts` 插件
|
||||
2. 配置 API 端點連接 HR Portal
|
||||
3. 從 HR Portal 取得員工授權的郵件帳號列表
|
||||
|
||||
詳見: [郵件系統設計文件](P:\porscheworld\2.專案設計區\3.MailSystem\郵件系統設計文件.md)
|
||||
|
||||
## 相關連結
|
||||
|
||||
- Keycloak Admin: https://auth.lab.taipei/admin
|
||||
- WebMail: https://webmail.porscheworld.tw
|
||||
- Roundcube OAuth2 Plugin: https://github.com/roundcube/roundcubemail-oauth2
|
||||
|
||||
## 完成檢查清單
|
||||
|
||||
- [ ] OAuth2 插件已安裝
|
||||
- [ ] `config/oauth2.inc.php` 設定完成
|
||||
- [ ] `config/config.inc.php` 啟用插件
|
||||
- [ ] Keycloak 使用者 email 正確設定
|
||||
- [ ] Roundcube 容器已重啟
|
||||
- [ ] SSO 登入測試成功
|
||||
- [ ] 郵件收發測試成功
|
||||
225
docs/architecture/01-系統架構設計.md
Normal file
225
docs/architecture/01-系統架構設計.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Virtual MIS - 系統架構設計
|
||||
|
||||
**版本**: v1.0
|
||||
**日期**: 2026-02-27
|
||||
**狀態**: 規劃中
|
||||
|
||||
---
|
||||
|
||||
## 系統架構圖
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 客戶企業 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 員工 A │ │ 員工 B │ │ 員工 C │ │ 管理者 │ │
|
||||
│ └─────┬────┘ └─────┬────┘ └─────┬────┘ └─────┬────┘ │
|
||||
└────────┼─────────────┼─────────────┼─────────────┼─────────┘
|
||||
│ │ │ │
|
||||
└─────────────┴─────────────┴─────────────┘
|
||||
│
|
||||
┌─────────▼─────────┐
|
||||
│ Virtual MIS │
|
||||
│ 統一入口 (SSO) │
|
||||
└─────────┬─────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
│ │ │
|
||||
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
||||
│ HR │ │ Service │ │ Billing │
|
||||
│ Portal │ │ Gateway │ │ System │
|
||||
└────┬────┘ └────┬────┘ └─────────┘
|
||||
│ │
|
||||
│ ┌──────────┼──────────┐
|
||||
│ │ │ │
|
||||
┌────▼────▼─┐ ┌────▼────┐ ┌──▼──────┐
|
||||
│ Mail │ │Calendar │ │ Drive │
|
||||
│ Service │ │Service │ │ Service │
|
||||
└───────────┘ └─────────┘ └─────────┘
|
||||
│
|
||||
┌────▼────┐
|
||||
│ Office │
|
||||
│ Service │
|
||||
└─────────┘
|
||||
```
|
||||
|
||||
## 核心模組
|
||||
|
||||
### 1. 租戶開通系統 (Tenant Onboarding)
|
||||
|
||||
**功能**:
|
||||
- 自動建立租戶資料
|
||||
- 網域配置與 DNS 設定
|
||||
- Keycloak Realm 建立
|
||||
- 服務初始化
|
||||
- 管理員帳號建立
|
||||
|
||||
**API 端點**:
|
||||
```
|
||||
POST /api/v1/tenant-onboarding
|
||||
GET /api/v1/tenant-onboarding/{tenant_id}
|
||||
PUT /api/v1/tenant-onboarding/{tenant_id}
|
||||
DELETE /api/v1/tenant-onboarding/{tenant_id}
|
||||
```
|
||||
|
||||
### 2. 服務整合閘道 (Service Integration Gateway)
|
||||
|
||||
**功能**:
|
||||
- Mail System API 整合
|
||||
- Calendar System API 整合
|
||||
- Drive System API 整合
|
||||
- Office System API 整合
|
||||
- 服務健康檢查
|
||||
- 統一錯誤處理
|
||||
|
||||
**API 端點**:
|
||||
```
|
||||
POST /api/v1/services/mail/create-account
|
||||
POST /api/v1/services/calendar/create-calendar
|
||||
POST /api/v1/services/drive/create-storage
|
||||
POST /api/v1/services/office/grant-access
|
||||
GET /api/v1/services/health
|
||||
```
|
||||
|
||||
### 3. 計費管理系統 (Billing System)
|
||||
|
||||
**功能**:
|
||||
- 訂閱方案管理
|
||||
- 使用量追蹤
|
||||
- 帳單生成
|
||||
- 金流整合 (綠界/藍新)
|
||||
- 自動續約/停權
|
||||
|
||||
**API 端點**:
|
||||
```
|
||||
POST /api/v1/billing/subscribe
|
||||
GET /api/v1/billing/invoices
|
||||
POST /api/v1/billing/payment
|
||||
GET /api/v1/billing/usage/{tenant_id}
|
||||
```
|
||||
|
||||
### 4. 管理後台 (Admin Portal)
|
||||
|
||||
**功能**:
|
||||
- 租戶管理
|
||||
- 服務監控儀表板
|
||||
- 使用量報表
|
||||
- 客戶支援工單
|
||||
- 系統配置
|
||||
|
||||
**頁面**:
|
||||
```
|
||||
/admin/dashboard - 總覽儀表板
|
||||
/admin/tenants - 租戶管理
|
||||
/admin/services - 服務狀態
|
||||
/admin/billing - 計費管理
|
||||
/admin/support - 客戶支援
|
||||
```
|
||||
|
||||
### 5. Landing Page (行銷頁面)
|
||||
|
||||
**功能**:
|
||||
- 服務介紹
|
||||
- 定價方案
|
||||
- 免費試用申請
|
||||
- 客戶見證
|
||||
- 聯絡表單
|
||||
|
||||
**頁面**:
|
||||
```
|
||||
/ - 首頁
|
||||
/pricing - 定價方案
|
||||
/features - 功能介紹
|
||||
/trial - 免費試用
|
||||
/contact - 聯絡我們
|
||||
```
|
||||
|
||||
## 資料庫設計
|
||||
|
||||
### 核心表
|
||||
|
||||
1. **tenants** - 租戶資料 (繼承 HR Portal)
|
||||
2. **subscriptions** - 訂閱記錄
|
||||
3. **invoices** - 帳單記錄
|
||||
4. **service_usage** - 服務使用記錄
|
||||
5. **support_tickets** - 客戶支援工單
|
||||
|
||||
## 技術選型
|
||||
|
||||
### 後端
|
||||
- **語言**: Python 3.11+
|
||||
- **框架**: FastAPI 0.115+
|
||||
- **ORM**: SQLAlchemy 2.0+
|
||||
- **驗證**: Pydantic v2
|
||||
- **任務隊列**: Celery + Redis
|
||||
|
||||
### 前端
|
||||
- **框架**: Next.js 15 (App Router)
|
||||
- **UI 庫**: Tailwind CSS + shadcn/ui
|
||||
- **狀態管理**: React Hooks + Context
|
||||
- **表單**: React Hook Form + Zod
|
||||
|
||||
### 基礎設施
|
||||
- **容器化**: Docker + Docker Compose
|
||||
- **反向代理**: Nginx
|
||||
- **SSL**: Let's Encrypt (Certbot)
|
||||
- **監控**: Prometheus + Grafana
|
||||
|
||||
## 部署架構
|
||||
|
||||
```
|
||||
Internet
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ Nginx Proxy │ (SSL Termination)
|
||||
└───────┬───────┘
|
||||
│
|
||||
┌───┴───┬───────┬───────┬───────┐
|
||||
│ │ │ │ │
|
||||
Admin Landing API HR Services
|
||||
Portal Page Gateway Portal (Mail/Cal/Drive)
|
||||
```
|
||||
|
||||
## 擴展性設計
|
||||
|
||||
### 水平擴展
|
||||
- API Gateway 支援多實例
|
||||
- 使用 Redis 作為共享快取
|
||||
- 資料庫讀寫分離
|
||||
|
||||
### 垂直擴展
|
||||
- 服務模組化設計
|
||||
- 微服務架構準備
|
||||
- 容器資源動態調整
|
||||
|
||||
## 安全性設計
|
||||
|
||||
1. **認證授權**:
|
||||
- Keycloak SSO
|
||||
- JWT Token
|
||||
- RBAC 權限控制
|
||||
|
||||
2. **資料安全**:
|
||||
- 資料加密傳輸 (TLS)
|
||||
- 敏感資料加密儲存
|
||||
- 定期備份
|
||||
|
||||
3. **網路安全**:
|
||||
- CORS 配置
|
||||
- Rate Limiting
|
||||
- DDoS 防護
|
||||
|
||||
## 監控與告警
|
||||
|
||||
- **服務健康**: 每分鐘檢查
|
||||
- **使用量追蹤**: 即時記錄
|
||||
- **錯誤日誌**: 集中管理
|
||||
- **性能指標**: CPU/記憶體/網路
|
||||
|
||||
---
|
||||
|
||||
**下一步**:
|
||||
1. 詳細 API 規格設計
|
||||
2. 資料庫 Schema 設計
|
||||
3. 開發環境建置
|
||||
213
docs/business/商業計畫.md
Normal file
213
docs/business/商業計畫.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# Virtual MIS - 商業計畫
|
||||
|
||||
**版本**: v1.0
|
||||
**日期**: 2026-02-27
|
||||
|
||||
---
|
||||
|
||||
## 市場分析
|
||||
|
||||
### 目標市場
|
||||
|
||||
**主要客群**:
|
||||
1. 新創公司 (5-20人)
|
||||
- 需要專業 IT 服務但沒有專職 IT 人員
|
||||
- 預算有限,希望降低 IT 成本
|
||||
|
||||
2. 中小企業 (20-50人)
|
||||
- 現有 IT 資源不足
|
||||
- 需要現代化的協作工具
|
||||
|
||||
3. 遠距團隊
|
||||
- 分散式辦公需求
|
||||
- 需要統一的協作平台
|
||||
|
||||
### 市場規模
|
||||
|
||||
- 台灣中小企業數量: 約 159 萬家 (2024)
|
||||
- 潛在客戶 (10-100人企業): 約 50 萬家
|
||||
- 目標市場滲透率 (3年): 0.1% = 500 家
|
||||
- 預估年營收 (3年): NT$ 9,000,000
|
||||
|
||||
## 競爭分析
|
||||
|
||||
### 主要競爭對手
|
||||
|
||||
| 服務商 | 優勢 | 劣勢 | 我們的差異化 |
|
||||
|--------|------|------|-------------|
|
||||
| Google Workspace | 知名度高、整合度好 | 價格較高、資料在國外 | 本地化、價格優勢 |
|
||||
| Microsoft 365 | 功能完整、企業級 | 複雜度高、價格高 | 簡單易用、中小企業專注 |
|
||||
| Zoho Workplace | 價格便宜 | 介面較舊、支援不佳 | 更好的 UX、在地支援 |
|
||||
|
||||
### 我們的優勢
|
||||
|
||||
1. **價格優勢**: 比 Google/Microsoft 便宜 50%
|
||||
2. **在地化**: 資料存放台灣、中文支援
|
||||
3. **整合性**: 一站式解決方案
|
||||
4. **彈性**: 可客製化配置
|
||||
5. **支援**: 在地技術支援
|
||||
|
||||
## 商業模式
|
||||
|
||||
### 訂閱制 SaaS
|
||||
|
||||
**定價策略**:
|
||||
|
||||
#### 測試期方案 (前 6 個月)
|
||||
|
||||
| 方案 | 人數 | 月費 | 年費 (85折) | 包含服務 |
|
||||
|------|------|------|------------|---------|
|
||||
| 基礎版 | 10人 | NT$ 500 | NT$ 5,100 | HR + Mail + Drive (5GB/人) |
|
||||
| 標準版 | 50人 | NT$ 1,500 | NT$ 15,300 | 基礎 + Calendar + Office |
|
||||
| 企業版 | 100人 | NT$ 3,000 | NT$ 30,600 | 標準 + 優先支援 + 10GB/人 |
|
||||
|
||||
#### 正式方案 (6 個月後)
|
||||
|
||||
| 方案 | 人數 | 月費 | 年費 (85折) |
|
||||
|------|------|------|------------|
|
||||
| 基礎版 | 10人 | NT$ 800 | NT$ 8,160 |
|
||||
| 標準版 | 50人 | NT$ 2,500 | NT$ 25,500 |
|
||||
| 企業版 | 100人 | NT$ 5,000 | NT$ 51,000 |
|
||||
|
||||
### 額外服務
|
||||
|
||||
- **超量使用**: NT$ 50/人/月
|
||||
- **額外儲存**: NT$ 100/10GB/月
|
||||
- **客製化開發**: 另報價
|
||||
- **專業服務**: NT$ 2,000/小時
|
||||
|
||||
## 營收預測
|
||||
|
||||
### 第一年 (2026)
|
||||
|
||||
| 月份 | 付費客戶 | 平均月費 | 月營收 | 累計營收 |
|
||||
|------|---------|---------|--------|---------|
|
||||
| M1-2 | 0 | - | NT$ 0 | NT$ 0 |
|
||||
| M3 | 3 | NT$ 1,000 | NT$ 3,000 | NT$ 3,000 |
|
||||
| M4 | 5 | NT$ 1,000 | NT$ 5,000 | NT$ 8,000 |
|
||||
| M5 | 8 | NT$ 1,000 | NT$ 8,000 | NT$ 16,000 |
|
||||
| M6 | 12 | NT$ 1,200 | NT$ 14,400 | NT$ 30,400 |
|
||||
| M7 | 15 | NT$ 1,200 | NT$ 18,000 | NT$ 48,400 |
|
||||
| M8 | 20 | NT$ 1,500 | NT$ 30,000 | NT$ 78,400 |
|
||||
| M9 | 25 | NT$ 1,500 | NT$ 37,500 | NT$ 115,900 |
|
||||
| M10 | 30 | NT$ 1,500 | NT$ 45,000 | NT$ 160,900 |
|
||||
| M11 | 35 | NT$ 1,500 | NT$ 52,500 | NT$ 213,400 |
|
||||
| M12 | 40 | NT$ 1,500 | NT$ 60,000 | NT$ 273,400 |
|
||||
|
||||
**第一年總營收**: NT$ 273,400
|
||||
|
||||
### 第二年目標
|
||||
|
||||
- 客戶數: 100 家
|
||||
- 平均月費: NT$ 2,000
|
||||
- 年營收: NT$ 2,400,000
|
||||
|
||||
### 第三年目標
|
||||
|
||||
- 客戶數: 200 家
|
||||
- 平均月費: NT$ 2,500
|
||||
- 年營收: NT$ 6,000,000
|
||||
|
||||
## 成本結構
|
||||
|
||||
### 固定成本 (月)
|
||||
|
||||
- 伺服器租用: NT$ 10,000
|
||||
- 網路頻寬: NT$ 5,000
|
||||
- SSL 憑證: NT$ 1,000
|
||||
- 備份儲存: NT$ 2,000
|
||||
- **小計**: NT$ 18,000/月
|
||||
|
||||
### 變動成本
|
||||
|
||||
- 客服人力: NT$ 50/客戶/月
|
||||
- 技術支援: NT$ 30/客戶/月
|
||||
- 行銷推廣: 營收的 20%
|
||||
|
||||
### 損益平衡點
|
||||
|
||||
固定成本 / (平均月費 - 變動成本) = 18,000 / (1,500 - 80) ≈ **13 個客戶**
|
||||
|
||||
## 行銷策略
|
||||
|
||||
### 獲客管道
|
||||
|
||||
1. **內容行銷** (免費)
|
||||
- 撰寫技術部落格
|
||||
- SEO 優化
|
||||
- 社群媒體經營
|
||||
|
||||
2. **口碑推薦** (低成本)
|
||||
- 推薦獎勵計畫
|
||||
- 客戶見證影片
|
||||
- 案例研究分享
|
||||
|
||||
3. **付費廣告** (初期投入)
|
||||
- Google Ads (關鍵字: 虛擬辦公室、企業郵件)
|
||||
- Facebook Ads (目標: 中小企業主)
|
||||
- LinkedIn Ads (B2B 客戶)
|
||||
|
||||
4. **合作夥伴**
|
||||
- 會計師事務所
|
||||
- 企業顧問公司
|
||||
- 創業加速器
|
||||
|
||||
### 客戶獲取成本 (CAC)
|
||||
|
||||
- 目標 CAC: NT$ 3,000/客戶
|
||||
- 客戶終身價值 (LTV): NT$ 36,000 (假設留存 2 年)
|
||||
- LTV/CAC 比: 12:1 (健康指標)
|
||||
|
||||
## 風險評估
|
||||
|
||||
### 主要風險
|
||||
|
||||
1. **技術風險**
|
||||
- 服務穩定性問題
|
||||
- 資料安全疑慮
|
||||
- **應對**: 完善測試、定期備份、安全稽核
|
||||
|
||||
2. **市場風險**
|
||||
- 客戶獲取困難
|
||||
- 競爭加劇
|
||||
- **應對**: 差異化定位、優質服務
|
||||
|
||||
3. **財務風險**
|
||||
- 初期現金流不足
|
||||
- 收款困難
|
||||
- **應對**: 預收年費、自動扣款
|
||||
|
||||
## 里程碑
|
||||
|
||||
### Phase 1: MVP (Week 1-6)
|
||||
- [ ] 完成系統開發
|
||||
- [ ] 內部測試
|
||||
- [ ] 準備行銷素材
|
||||
|
||||
### Phase 2: Beta (Week 7-8)
|
||||
- [ ] 招募 5 家測試客戶
|
||||
- [ ] 收集回饋改進
|
||||
- [ ] 優化使用者體驗
|
||||
|
||||
### Phase 3: Launch (Week 9-12)
|
||||
- [ ] 正式對外發布
|
||||
- [ ] 啟動行銷活動
|
||||
- [ ] 目標達成 10 個付費客戶
|
||||
|
||||
### Phase 4: Growth (Month 4-12)
|
||||
- [ ] 持續優化產品
|
||||
- [ ] 擴大行銷投入
|
||||
- [ ] 目標達成 40 個付費客戶
|
||||
|
||||
## 退場策略
|
||||
|
||||
1. **被收購**: 目標估值 NT$ 30,000,000 (3 年後)
|
||||
2. **持續經營**: 建立穩定現金流
|
||||
3. **技術授權**: 授權給大型企業
|
||||
|
||||
---
|
||||
|
||||
**下一步行動**:
|
||||
1. 完成 MVP 開發
|
||||
2. 準備行銷素材
|
||||
3. 洽談 Beta 測試客戶
|
||||
373
docs/開發規範.md
Normal file
373
docs/開發規範.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Virtual MIS - 開發規範
|
||||
|
||||
**版本**: v1.0
|
||||
**日期**: 2026-02-27
|
||||
|
||||
---
|
||||
|
||||
## 專案結構
|
||||
|
||||
```
|
||||
virtual-mis/
|
||||
├── backend/ # 後端服務
|
||||
│ ├── app/
|
||||
│ │ ├── api/ # API 路由
|
||||
│ │ │ ├── v1/
|
||||
│ │ │ │ ├── tenant_onboarding.py
|
||||
│ │ │ │ ├── service_integration.py
|
||||
│ │ │ │ └── billing.py
|
||||
│ │ │ └── router.py
|
||||
│ │ ├── core/ # 核心配置
|
||||
│ │ │ ├── config.py
|
||||
│ │ │ ├── security.py
|
||||
│ │ │ └── dependencies.py
|
||||
│ │ ├── db/ # 資料庫
|
||||
│ │ │ ├── base.py
|
||||
│ │ │ └── session.py
|
||||
│ │ ├── models/ # ORM 模型
|
||||
│ │ ├── schemas/ # Pydantic Schema
|
||||
│ │ ├── services/ # 業務邏輯
|
||||
│ │ └── utils/ # 工具函數
|
||||
│ ├── alembic/ # 資料庫遷移
|
||||
│ ├── tests/ # 測試
|
||||
│ ├── .env # 環境變數
|
||||
│ ├── requirements.txt # 依賴套件
|
||||
│ └── main.py # 應用入口
|
||||
│
|
||||
├── frontend/ # 前端服務
|
||||
│ ├── admin-portal/ # 管理後台
|
||||
│ │ ├── app/ # Next.js App Router
|
||||
│ │ ├── components/ # React 元件
|
||||
│ │ ├── lib/ # 工具函數
|
||||
│ │ ├── public/ # 靜態資源
|
||||
│ │ └── package.json
|
||||
│ │
|
||||
│ └── landing-page/ # 行銷頁面
|
||||
│ ├── app/
|
||||
│ ├── components/
|
||||
│ └── package.json
|
||||
│
|
||||
└── docs/ # 文件
|
||||
├── architecture/ # 架構設計
|
||||
├── api-specs/ # API 規格
|
||||
├── business/ # 商業計畫
|
||||
└── deployment/ # 部署文件
|
||||
```
|
||||
|
||||
## 開發環境
|
||||
|
||||
### 後端環境
|
||||
|
||||
**Python 版本**: 3.11+
|
||||
|
||||
**Port 配置**:
|
||||
- 開發環境: `10281`
|
||||
- 測試環境: `10282`
|
||||
|
||||
**資料庫**:
|
||||
- Host: `10.1.0.20`
|
||||
- Port: `5433`
|
||||
- Database: `virtual_mis`
|
||||
- User: `admin`
|
||||
|
||||
**啟動方式**:
|
||||
```bash
|
||||
cd D:\_Develop\porscheworld_develop\virtual-mis\backend
|
||||
START_BACKEND.bat
|
||||
```
|
||||
|
||||
### 前端環境
|
||||
|
||||
**Node.js 版本**: 20+
|
||||
|
||||
**Port 配置**:
|
||||
- Admin Portal: `10280`
|
||||
- Landing Page: `10290`
|
||||
|
||||
**啟動方式**:
|
||||
```bash
|
||||
cd D:\_Develop\porscheworld_develop\virtual-mis\frontend\admin-portal
|
||||
START_FRONTEND.bat
|
||||
```
|
||||
|
||||
## 編碼規範
|
||||
|
||||
### Python (後端)
|
||||
|
||||
1. **命名規範**:
|
||||
- 檔案名稱: `snake_case.py`
|
||||
- 類別名稱: `PascalCase`
|
||||
- 函數名稱: `snake_case`
|
||||
- 常數: `UPPER_CASE`
|
||||
|
||||
2. **程式碼風格**:
|
||||
- 使用 Black 格式化
|
||||
- 遵循 PEP 8
|
||||
- 最大行長: 100 字元
|
||||
|
||||
3. **型別標註**:
|
||||
```python
|
||||
def get_tenant(tenant_id: int) -> Optional[Tenant]:
|
||||
"""取得租戶資料"""
|
||||
pass
|
||||
```
|
||||
|
||||
4. **文件字串**:
|
||||
```python
|
||||
def create_tenant(data: TenantCreate) -> Tenant:
|
||||
"""
|
||||
建立新租戶
|
||||
|
||||
Args:
|
||||
data: 租戶建立資料
|
||||
|
||||
Returns:
|
||||
Tenant: 建立的租戶物件
|
||||
|
||||
Raises:
|
||||
ValueError: 租戶代碼已存在
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
### TypeScript (前端)
|
||||
|
||||
1. **命名規範**:
|
||||
- 檔案名稱: `kebab-case.tsx`
|
||||
- 元件名稱: `PascalCase`
|
||||
- 函數名稱: `camelCase`
|
||||
- 介面: `PascalCase` (前綴 I 可選)
|
||||
|
||||
2. **元件結構**:
|
||||
```typescript
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
onSubmit: (data: FormData) => void
|
||||
}
|
||||
|
||||
export default function MyComponent({ title, onSubmit }: Props) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
3. **型別定義**:
|
||||
```typescript
|
||||
// types/tenant.ts
|
||||
export interface Tenant {
|
||||
id: number
|
||||
code: string
|
||||
name: string
|
||||
status: 'trial' | 'active' | 'suspended'
|
||||
}
|
||||
```
|
||||
|
||||
## API 設計規範
|
||||
|
||||
### RESTful 規範
|
||||
|
||||
**URL 命名**:
|
||||
- 使用名詞複數: `/api/v1/tenants`
|
||||
- 使用 kebab-case: `/api/v1/tenant-onboarding`
|
||||
- 版本控制: `/api/v1/`, `/api/v2/`
|
||||
|
||||
**HTTP 方法**:
|
||||
- `GET`: 查詢資料
|
||||
- `POST`: 建立資料
|
||||
- `PUT`: 完整更新
|
||||
- `PATCH`: 部分更新
|
||||
- `DELETE`: 刪除資料
|
||||
|
||||
**回應格式**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "測試公司"
|
||||
},
|
||||
"message": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**錯誤回應**:
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "TENANT_NOT_FOUND",
|
||||
"message": "找不到指定的租戶",
|
||||
"details": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schema 設計
|
||||
|
||||
**命名規範**:
|
||||
- Base Schema: `TenantBase`
|
||||
- Create Schema: `TenantCreate`
|
||||
- Update Schema: `TenantUpdate`
|
||||
- Response Schema: `TenantResponse`
|
||||
|
||||
**範例**:
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class TenantBase(BaseModel):
|
||||
"""租戶基礎 Schema"""
|
||||
code: str = Field(..., max_length=50, description="租戶代碼")
|
||||
name: str = Field(..., max_length=200, description="公司名稱")
|
||||
|
||||
class TenantCreate(TenantBase):
|
||||
"""建立租戶 Schema"""
|
||||
admin_email: str = Field(..., description="管理員郵箱")
|
||||
|
||||
class TenantResponse(TenantBase):
|
||||
"""租戶回應 Schema"""
|
||||
id: int
|
||||
status: str
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
```
|
||||
|
||||
## 資料庫規範
|
||||
|
||||
### Migration 管理
|
||||
|
||||
**命名規則**:
|
||||
```
|
||||
{timestamp}_{description}.py
|
||||
例如: 20260227_create_subscriptions_table.py
|
||||
```
|
||||
|
||||
**Migration 內容**:
|
||||
```python
|
||||
def upgrade() -> None:
|
||||
"""升級操作"""
|
||||
op.create_table(
|
||||
'subscriptions',
|
||||
sa.Column('id', sa.Integer(), primary_key=True),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
# ...
|
||||
)
|
||||
|
||||
def downgrade() -> None:
|
||||
"""降級操作"""
|
||||
op.drop_table('subscriptions')
|
||||
```
|
||||
|
||||
### 表格命名
|
||||
|
||||
- 使用複數形式: `subscriptions`, `invoices`
|
||||
- 使用 snake_case
|
||||
- 加入前綴表示模組: `billing_invoices`
|
||||
|
||||
## Git 工作流程
|
||||
|
||||
### 分支策略
|
||||
|
||||
- `master`: 生產環境
|
||||
- `develop`: 開發環境
|
||||
- `feature/*`: 功能開發
|
||||
- `hotfix/*`: 緊急修復
|
||||
|
||||
### Commit 訊息
|
||||
|
||||
**格式**:
|
||||
```
|
||||
<類型>: <簡短描述>
|
||||
|
||||
<詳細說明>
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
**類型**:
|
||||
- `feat`: 新功能
|
||||
- `fix`: 錯誤修復
|
||||
- `docs`: 文件更新
|
||||
- `refactor`: 重構
|
||||
- `test`: 測試
|
||||
- `chore`: 雜項
|
||||
|
||||
**範例**:
|
||||
```
|
||||
feat: 新增租戶開通 API
|
||||
|
||||
實作租戶自動開通功能,包含:
|
||||
- 建立租戶資料
|
||||
- 配置網域
|
||||
- 建立 Keycloak Realm
|
||||
- 初始化服務
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## 測試規範
|
||||
|
||||
### 單元測試
|
||||
|
||||
**覆蓋率目標**: 80%+
|
||||
|
||||
**測試檔案命名**:
|
||||
```
|
||||
tests/
|
||||
├── unit/
|
||||
│ ├── test_tenant_service.py
|
||||
│ └── test_billing_service.py
|
||||
└── integration/
|
||||
├── test_api_tenants.py
|
||||
└── test_api_billing.py
|
||||
```
|
||||
|
||||
**測試範例**:
|
||||
```python
|
||||
import pytest
|
||||
from app.services.tenant_service import create_tenant
|
||||
|
||||
def test_create_tenant_success():
|
||||
"""測試建立租戶成功"""
|
||||
data = TenantCreate(
|
||||
code="testcompany",
|
||||
name="測試公司",
|
||||
admin_email="admin@test.com"
|
||||
)
|
||||
|
||||
tenant = create_tenant(data)
|
||||
|
||||
assert tenant.code == "testcompany"
|
||||
assert tenant.status == "trial"
|
||||
```
|
||||
|
||||
## 安全規範
|
||||
|
||||
1. **環境變數**: 所有敏感資訊放在 `.env`
|
||||
2. **密碼處理**: 使用 bcrypt 雜湊
|
||||
3. **API 驗證**: 所有 API 需要 JWT token
|
||||
4. **輸入驗證**: 使用 Pydantic 驗證所有輸入
|
||||
5. **SQL 注入**: 使用 ORM,避免原生 SQL
|
||||
|
||||
## 文件規範
|
||||
|
||||
1. **README.md**: 每個專案必須包含
|
||||
2. **API 文件**: 使用 FastAPI 自動生成 (Swagger)
|
||||
3. **程式碼註解**: 複雜邏輯必須註解
|
||||
4. **設計文件**: 重要功能需要設計文件
|
||||
|
||||
---
|
||||
|
||||
**參考資源**:
|
||||
- [FastAPI 官方文件](https://fastapi.tiangolo.com/)
|
||||
- [Next.js 官方文件](https://nextjs.org/docs)
|
||||
- [Python PEP 8](https://peps.python.org/pep-0008/)
|
||||
Reference in New Issue
Block a user