Files
vmis/docs/開發規範.md
VMIS Developer 62baadb06f 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>
2026-03-15 15:31:37 +08:00

8.0 KiB
Raw Blame History

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 (後端)

  1. 命名規範:

    • 檔案名稱: snake_case.py
    • 類別名稱: PascalCase
    • 函數名稱: snake_case
    • 常數: UPPER_CASE
  2. 程式碼風格:

    • 使用 Black 格式化
    • 遵循 PEP 8
    • 最大行長: 100 字元
  3. 型別標註:

    def get_tenant(tenant_id: int) -> Optional[Tenant]:
        """取得租戶資料"""
        pass
    
  4. 文件字串:

    def create_tenant(data: TenantCreate) -> Tenant:
        """
        建立新租戶
    
        Args:
            data: 租戶建立資料
    
        Returns:
            Tenant: 建立的租戶物件
    
        Raises:
            ValueError: 租戶代碼已存在
        """
        pass
    

TypeScript (前端)

  1. 命名規範:

    • 檔案名稱: kebab-case.tsx
    • 元件名稱: PascalCase
    • 函數名稱: camelCase
    • 介面: PascalCase (前綴 I 可選)
  2. 元件結構:

    '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. 型別定義:

    // 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"

安全規範

  1. 環境變數: 所有敏感資訊放在 .env
  2. 密碼處理: 使用 bcrypt 雜湊
  3. API 驗證: 所有 API 需要 JWT token
  4. 輸入驗證: 使用 Pydantic 驗證所有輸入
  5. SQL 注入: 使用 ORM避免原生 SQL

文件規範

  1. README.md: 每個專案必須包含
  2. API 文件: 使用 FastAPI 自動生成 (Swagger)
  3. 程式碼註解: 複雜邏輯必須註解
  4. 設計文件: 重要功能需要設計文件

參考資源: