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>
8.0 KiB
8.0 KiB
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
啟動方式:
cd D:\_Develop\porscheworld_develop\virtual-mis\backend
START_BACKEND.bat
前端環境
Node.js 版本: 20+
Port 配置:
- Admin Portal:
10280 - Landing Page:
10290
啟動方式:
cd D:\_Develop\porscheworld_develop\virtual-mis\frontend\admin-portal
START_FRONTEND.bat
編碼規範
Python (後端)
-
命名規範:
- 檔案名稱:
snake_case.py - 類別名稱:
PascalCase - 函數名稱:
snake_case - 常數:
UPPER_CASE
- 檔案名稱:
-
程式碼風格:
- 使用 Black 格式化
- 遵循 PEP 8
- 最大行長: 100 字元
-
型別標註:
def get_tenant(tenant_id: int) -> Optional[Tenant]: """取得租戶資料""" pass -
文件字串:
def create_tenant(data: TenantCreate) -> Tenant: """ 建立新租戶 Args: data: 租戶建立資料 Returns: Tenant: 建立的租戶物件 Raises: ValueError: 租戶代碼已存在 """ pass
TypeScript (前端)
-
命名規範:
- 檔案名稱:
kebab-case.tsx - 元件名稱:
PascalCase - 函數名稱:
camelCase - 介面:
PascalCase(前綴 I 可選)
- 檔案名稱:
-
元件結構:
'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> ) } -
型別定義:
// 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: 刪除資料
回應格式:
{
"success": true,
"data": {
"id": 1,
"name": "測試公司"
},
"message": "操作成功"
}
錯誤回應:
{
"success": false,
"error": {
"code": "TENANT_NOT_FOUND",
"message": "找不到指定的租戶",
"details": {}
}
}
Schema 設計
命名規範:
- Base Schema:
TenantBase - Create Schema:
TenantCreate - Update Schema:
TenantUpdate - Response Schema:
TenantResponse
範例:
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 內容:
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
測試範例:
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"
安全規範
- 環境變數: 所有敏感資訊放在
.env - 密碼處理: 使用 bcrypt 雜湊
- API 驗證: 所有 API 需要 JWT token
- 輸入驗證: 使用 Pydantic 驗證所有輸入
- SQL 注入: 使用 ORM,避免原生 SQL
文件規範
- README.md: 每個專案必須包含
- API 文件: 使用 FastAPI 自動生成 (Swagger)
- 程式碼註解: 複雜邏輯必須註解
- 設計文件: 重要功能需要設計文件
參考資源: