- 新增 src/utils/timezone.py 時區工具函式 - 修改 11 個後端檔案,全部改用 now_taipei() - 更新 HARD_RULES.md 加入時區鐵律章節 - 更新 Skills 02/04 加入時區禁令 🔴 HARD RULE: 禁止 datetime.utcnow() / datetime.now(UTC) ✅ 正確做法: from src.utils.timezone import now_taipei Memory: feedback_timezone_taipei.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
305 lines
7.7 KiB
Markdown
305 lines
7.7 KiB
Markdown
# AWOOOI 絕對禁止規則 (Hard Rules)
|
||
|
||
> 違反任何一條 = 重大事故
|
||
|
||
## 快速索引
|
||
|
||
| 主題 | 禁止 | 正確做法 | 詳細規則 |
|
||
|------|------|---------|---------|
|
||
| CI/CD | `ubuntu-latest` | `self-hosted` | [→ GitHub Billing](#github-billing) |
|
||
| Telegram | `logOut()` | 先停後換 | [→ Telegram Token](#telegram-token) |
|
||
| 前端 | 硬編碼文字 | `next-intl` | [→ i18n](#i18n) |
|
||
| 資料庫 | SQLite | PostgreSQL | [→ DB](#database) |
|
||
| CORS | `*` | 白名單 | [→ CORS](#cors) |
|
||
| 數據 | 假數據 Demo | 真實 API | [→ No Fake Data](#no-fake-data) |
|
||
| 架構 | 刪除 OpenClaw | OpenClaw 是核心 | [→ OpenClaw](#openclaw) |
|
||
| Git | `--force` | 正常 push | [→ Git Safety](#git-safety) |
|
||
| **測試** | **Mock 測試** | **真實 DB/服務** | [→ No Mock Testing](#no-mock-testing) |
|
||
| **API** | **單獨改路徑** | **前後端同步** | [→ API Path Naming](#api-path-naming) |
|
||
| **部署** | **假設已部署** | **驗證 Pod 版本** | [→ Deployment Verification](#deployment-verification) |
|
||
| **Alertmanager** | **指向 OpenClaw** | **指向 AWOOOI API** | [→ Alertmanager Routing](#alertmanager-routing) |
|
||
| **簽核 UI** | **清空內容** | **保留原始內容** | [→ Approval Preserve Content](#approval-preserve-content) |
|
||
| **時區** | **UTC/utcnow** | **台北時區 +8** | [→ Timezone Taipei](#timezone-taipei) |
|
||
|
||
---
|
||
|
||
## GitHub Billing
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_github_billing.md`
|
||
|
||
```yaml
|
||
# ❌ 禁止
|
||
runs-on: ubuntu-latest
|
||
|
||
# ✅ 正確
|
||
runs-on: self-hosted
|
||
```
|
||
|
||
**原因:** GitHub Actions 帳戶額度限制,必須用 192.168.0.110 的 self-hosted runner。
|
||
|
||
---
|
||
|
||
## Telegram Token
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_telegram_token_disaster.md`
|
||
|
||
```python
|
||
# ❌ 禁止 - 會導致 Token 永久失效
|
||
await bot.log_out()
|
||
|
||
# ✅ 正確流程
|
||
1. 先停止舊 Bot 的 Long Polling
|
||
2. 再切換新 Token
|
||
```
|
||
|
||
**原因:** 2026-03-23 災難事件,logOut 導致 Token 永久失效。
|
||
|
||
---
|
||
|
||
## i18n
|
||
|
||
**Memory:**
|
||
- `feedback_i18n_zero_hardcode.md` - 零容忍硬編碼
|
||
- `feedback_i18n_language_strategy.md` - 語言選擇標準
|
||
|
||
```tsx
|
||
// ❌ 禁止硬編碼
|
||
<button>Submit</button>
|
||
<span>STATE: IDLE</span>
|
||
|
||
// ✅ 使用 next-intl
|
||
<button>{t('common.submit')}</button>
|
||
<span>{t('agent.state')}: {t('agent.idle')}</span>
|
||
```
|
||
|
||
| 元素 | 語言 | 範例 |
|
||
|------|------|------|
|
||
| UI 文字 | 繁體中文 | 「系統穩定」 |
|
||
| 技術標識 | 英文 | `P0`, `RESOLVED` |
|
||
|
||
**原因:** 面向使用者的文字必須繁體中文。
|
||
|
||
---
|
||
|
||
## Database
|
||
|
||
**Memory:** AWOOOI 憲法
|
||
|
||
```python
|
||
# ❌ 禁止
|
||
DATABASE_URL = "sqlite:///..."
|
||
|
||
# ✅ 正確
|
||
DATABASE_URL = "postgresql+asyncpg://..."
|
||
```
|
||
|
||
**原因:** SQLite 無法支援生產環境並發。
|
||
|
||
---
|
||
|
||
## CORS
|
||
|
||
**Memory:** AWOOOI 憲法
|
||
|
||
```python
|
||
# ❌ 禁止
|
||
CORS_ORIGINS = ["*"]
|
||
|
||
# ✅ 正確
|
||
CORS_ORIGINS = ["https://awoooi.wooo.work", "http://localhost:3000"]
|
||
```
|
||
|
||
**原因:** 安全性要求。
|
||
|
||
---
|
||
|
||
## No Fake Data
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_no_fake_data.md`
|
||
|
||
```tsx
|
||
// ❌ 禁止
|
||
const data = DEMO_DATA
|
||
|
||
// ✅ 正確
|
||
const { data } = useRealAPI()
|
||
```
|
||
|
||
**原因:** 假數據導致用戶無法看到真實系統狀態。
|
||
|
||
---
|
||
|
||
## OpenClaw
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_architecture_openclaw_core.md`
|
||
|
||
```
|
||
❌ 禁止: 淘汰、取代、或刪除 OpenClaw
|
||
✅ 正確: OpenClaw 是 AWOOOI 產品核心,只能增強不能移除
|
||
```
|
||
|
||
**原因:** OpenClaw AI 是產品核心價值。
|
||
|
||
---
|
||
|
||
## Git Safety
|
||
|
||
**Memory:** 防禦性工程
|
||
|
||
```bash
|
||
# ❌ 禁止
|
||
git push --force
|
||
git reset --hard
|
||
git checkout -- .
|
||
|
||
# ✅ 正確
|
||
git push
|
||
git revert
|
||
```
|
||
|
||
**原因:** 防止資料遺失。
|
||
|
||
---
|
||
|
||
## API Path Naming
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_api_path_naming.md`
|
||
|
||
```python
|
||
# ❌ 禁止 - 單獨修改後端路徑
|
||
@router.get("/ai-performance") # 改成 /incidents/ai-performance
|
||
# 但前端仍調用 /ai-performance → 404
|
||
|
||
# ✅ 正確 - 前後端同步修改
|
||
# 1. 後端: @router.get("/incidents/ai-performance")
|
||
# 2. 前端: await fetch('/api/v1/stats/incidents/ai-performance')
|
||
# 3. 測試: curl 驗證
|
||
```
|
||
|
||
**原因:** 路徑變更是破壞性變更,必須同時更新前後端。
|
||
|
||
---
|
||
|
||
## No Mock Testing
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_no_mock_testing.md`
|
||
|
||
```python
|
||
# ❌ 禁止 - 全面禁止 Mock 測試
|
||
from unittest.mock import Mock, AsyncMock, MagicMock, patch
|
||
mock_service = AsyncMock()
|
||
with patch("src.services.xxx", mock_service):
|
||
...
|
||
|
||
# ✅ 正確 - 使用真實資料庫/服務
|
||
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
|
||
response = await client.post("/api/v1/xxx", json=payload)
|
||
```
|
||
|
||
**原因:** 統帥 2026-03-24 明確指示「全面禁止!!!」Mock 無法反映真實系統行為。
|
||
|
||
**允許例外:**
|
||
- `patch.object(settings, ...)` 修改配置值(非 Mock 服務)
|
||
|
||
---
|
||
|
||
## Deployment Verification
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_deployment_verification.md`
|
||
|
||
```bash
|
||
# ❌ 禁止 - 假設 git push 就是部署完成
|
||
git push && echo "已部署"
|
||
|
||
# ✅ 正確 - 必須驗證 Pod 實際運行版本
|
||
# 1. 確認 CD workflow 成功
|
||
gh run list --workflow=cd.yaml --limit 1 # 必須 ✅ success
|
||
|
||
# 2. 驗證 Pod 鏡像版本
|
||
kubectl get pods -n awoooi-prod -o jsonpath="{.items[*].spec.containers[*].image}"
|
||
# 鏡像 tag 必須與最新 commit SHA 匹配
|
||
|
||
# 3. Health check
|
||
curl -f https://api.awoooi.wooo.work/api/v1/health
|
||
```
|
||
|
||
**原因:** 2026-03-24 重大事故:代碼已提交但 CD 連續失敗,正式環境仍運行舊版本,用戶誤以為功能已修復。
|
||
|
||
---
|
||
|
||
## Alertmanager Routing
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_alertmanager_awoooi_flow.md`
|
||
|
||
```yaml
|
||
# ❌ 禁止 - 指向 OpenClaw (會使用舊 AIOPS 格式)
|
||
receivers:
|
||
- name: openclaw
|
||
webhook_configs:
|
||
- url: 'http://192.168.0.188:8088/api/v1/webhook/alertmanager'
|
||
|
||
# ✅ 正確 - 指向 AWOOOI API (K3s)
|
||
receivers:
|
||
- name: awoooi
|
||
webhook_configs:
|
||
- url: 'http://192.168.0.120:32334/api/v1/webhooks/alertmanager'
|
||
```
|
||
|
||
**職責分工:**
|
||
|
||
| 系統 | 職責 | Telegram 權限 |
|
||
|------|------|--------------|
|
||
| AWOOOI API (K3s 32334) | 告警處理 + 格式化 + 發送 | ✅ |
|
||
| OpenClaw (188:8088) | AI 大腦、LLM 分析 | ❌ |
|
||
|
||
**原因:** 2026-03-25 災難:Claude 錯誤將 Alertmanager 指向 OpenClaw,導致 Telegram 發送舊 AIOPS 格式(🤝 [協同警報]),而非 AWOOOI 格式(═══ 🚨 CRITICAL ═══)。
|
||
|
||
---
|
||
|
||
## Approval Preserve Content
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_approval_preserve_content.md`
|
||
|
||
```tsx
|
||
// ❌ 禁止 - 簽核後清空內容
|
||
if (approval.status === 'approved') {
|
||
return <div>已批准</div> // 原始內容不見了!
|
||
}
|
||
|
||
// ✅ 正確 - 保留原始內容
|
||
<Badge>已批准</Badge>
|
||
<OriginalAlertContent alert={approval} /> {/* 保留! */}
|
||
<ExecutionResult result={approval.result} />
|
||
```
|
||
|
||
**原因:** 2026-03-25 統帥指示:簽核後必須保留原始告警內容,用戶需要回顧已處理的告警。
|
||
|
||
---
|
||
|
||
## Timezone Taipei
|
||
|
||
**Memory:** `~/.claude/projects/-Users-ogt-awoooi/memory/feedback_timezone_taipei.md`
|
||
|
||
```python
|
||
# ❌ 禁止 - UTC 時區
|
||
from datetime import UTC
|
||
datetime.now(UTC)
|
||
datetime.utcnow()
|
||
|
||
# ✅ 正確 - 台北時區
|
||
from src.utils.timezone import now_taipei, now_taipei_iso
|
||
now_taipei() # datetime with +08:00
|
||
now_taipei_iso() # '2026-03-25T02:08:04+08:00'
|
||
```
|
||
|
||
**原因:** 統帥在台灣,日誌和 Telegram 告警必須顯示台北時間 (UTC+8),方便閱讀無需心算。
|
||
|
||
---
|
||
|
||
## 如何新增規則
|
||
|
||
1. 在此文件新增章節
|
||
2. 更新快速索引表
|
||
3. 在 Memory 新增對應 `feedback_*.md`
|
||
4. 更新 `MEMORY.md` 索引
|