Files
star-erp/.agents/rules/activity-logging.md
sky121113 deef3baacc
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 57s
refactor: 重構模組通訊與調整儀表板功能
- 依循跨模組通訊規範,將 Sales 與 Production 模組中對 Inventory 的直接模型關聯改為透過 InventoryServiceInterface 取得
- 於 InventoryService 實作獲取最高庫存價值、即將過期商品等方法,供儀表板使用
- 確保所有跨模組調用皆採用手動水和(Manual Hydration)方式組合資料
- 移除本地已歸檔的 .agent 規範檔案
2026-02-25 11:48:52 +08:00

116 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
trigger: always_on
---
---
name: 操作紀錄實作規範
description: 規範系統內 Activity Log 的實作標準,包含自動名稱解析、複雜單據合併記錄、與前端顯示優化。
---
# 操作紀錄實作規範 (Activity Logging Skill)
本文件定義了 Star ERP 系統中操作紀錄的最高實作標準,旨在確保每筆日誌都具有「高度可讀性」與「單一性」。
---
## 1. 後端實作核心 (Backend)
### 1.1 全域 ID 轉名稱邏輯 (Global ID Resolution)
為了讓管理者能直覺看懂日誌,所有的 ID`warehouse_id`, `created_by`)在記錄時都應自動解析為名稱。此邏輯應統一在 Model 的 `tapActivity` 中實作。
#### 關鍵實作參考:
```php
public function tapActivity(\Spatie\Activitylog\Contracts\Activity $activity, string $eventName)
{
// 🚩 核心:轉換為陣列以避免 Indirect modification error
$properties = $activity->properties instanceof \Illuminate\Support\Collection
? $activity->properties->toArray()
: $activity->properties;
// 1. Snapshot 快照:用於主描述的上下文(例如:單號、名稱)
$snapshot = $properties['snapshot'] ?? [];
$snapshot['doc_no'] = $this->doc_no;
$snapshot['warehouse_name'] = $this->warehouse?->name;
$properties['snapshot'] = $snapshot;
// 2. 名稱解析:自動將 attributes 與 old 中的 ID 換成人名/物名
$resolver = function (&$data) {
if (empty($data) || !is_array($data)) return;
// 使用者 ID 轉換
foreach (['created_by', 'updated_by', 'completed_by'] as $f) {
if (isset($data[$f]) && is_numeric($data[$f])) {
$data[$f] = \App\Modules\Core\Models\User::find($data[$f])?->name;
}
}
// 倉庫 ID 轉換
if (isset($data['warehouse_id']) && is_numeric($data['warehouse_id'])) {
$data['warehouse_id'] = \App\Modules\Inventory\Models\Warehouse::find($data['warehouse_id'])?->name;
}
};
if (isset($properties['attributes'])) $resolver($properties['attributes']);
if (isset($properties['old'])) $resolver($properties['old']);
$activity->properties = $properties;
}
```
### 1.2 複雜操作的日誌合併 (Log Consolidation)
當一個操作同時涉及「多個品項異動」與「單據狀態變更」時,**嚴禁**產生多筆重複日誌。
* **策略**:在 Service 層手動發送主日誌,並使用 `saveQuietly()` 更新單據屬性以抑止 Trait 的自動日誌。
* **格式**:主日誌應包含 `items_diff` (品項差異) 與 `attributes/old` (單據狀態變更)。
```php
// Service 中的實作方式
DB::transaction(function () use ($doc, $items) {
// 1. 更新品項 (記錄變動細節)
$updatedItems = $this->getUpdatedItems($doc, $items);
// 2. 靜默更新單據狀態 (避免 Trait 產生冗餘日誌)
$doc->status = 'completed';
$doc->saveQuietly();
// 3. 手動觸發單一合併日誌
activity()
->performedOn($doc)
->withProperties([
'items_diff' => ['updated' => $updatedItems],
'attributes' => ['status' => 'completed'],
'old' => ['status' => 'counting']
])
->log('updated');
});
```
---
## 2. 前端介面規範 (Frontend)
### 2.1 標籤命名規範 (Field Labels)
前端顯示應完全移除「ID」字眼提供最友善的閱讀體驗。
**檔案位置**: `resources/js/Components/ActivityLog/ActivityDetailDialog.tsx`
```typescript
const fieldLabels: Record<string, string> = {
warehouse_id: '倉庫', // ❌ 禁用「倉庫 ID」
created_by: '建立者', // ❌ 禁用「建立者 ID」
completed_by: '完成者',
status: '狀態',
};
```
### 2.2 特殊結構顯示
* **品項異動**:前端應能渲染 `items_diff` 結構,以「品項名稱 + 數值變動」的方式呈現表格(已在 `ActivityDetailDialog` 實作)。
---
## 3. 開發檢核清單 (Checklist)
- [ ] **Model**: `tapActivity` 是否已處理 Collection 快照?
- [ ] **Model**: 是否已實作全域 ID 至名稱的自動解析?
- [ ] **Service**: 是否使用 `saveQuietly()` 避免產生重複的「單據已更新」日誌?
- [ ] **UI**: `fieldLabels` 是否已移除所有「ID」字樣
- [ ] **UI**: 若有品項異動,是否已正確格式化傳入 `items_diff`