← Financial Cloud Cloud Cloud Club · 建構文章

極點宏觀|Financial Cloud Cloud · 建構文章

Kiro:從零建置 Fab SPC Drift Synchronization Portal

系列: Kiro 工作坊

文章: 22

文章
Kiro 工作坊
01 使用 Kiro 建置:他加祿語學習 App 的提示優先產品設計工作坊
Kiro 工作坊
02 使用 Kiro 建置:他加祿語 學習 App 的教育優先開發技巧工作坊
Kiro 工作坊
03 使用 Kiro 建置:他加祿語 學習 App 的深入開發流程工作坊
Kiro 工作坊
04 使用 Kiro 建置:將 他加祿語 學習 App 在地化為中文變體工作坊
Kiro 工作坊
05 使用 Kiro 建置:他加祿語 卡片的文法與發音補強管線工作坊
Kiro 工作坊
06 使用 Kiro 建置:他加祿語 學習 App 中可審查的獨特額外例句工作坊
Kiro 工作坊
07 與 Kiro 同行:晶圓廠工程健康度 Hook 工作坊
Kiro 工作坊
08 與 Kiro 同行:蝕刻製程視窗風險測試自動化工作坊
Kiro 工作坊
09 與 Kiro 同行:黃光微影漂移風險開發工作坊
Kiro 工作坊
10 工程團隊入門 — 日常工廠值班使用 fab spc drift sync portal
Kiro 工作坊
11 工程團隊附錄 — fab spc drift sync portal 的日常工廠值班使用
Kiro 工作坊
12 Kiro:規格驅動工廠軟體的現場工程工作坊
Kiro 工作坊
13 Kiro:實作 Lab — 從零建置具型別的 Factory Risk Portal
Kiro 工作坊
14 Kiro:工程開發人員的提示、程式碼和型別標準手冊
Kiro 工作坊
15 Kiro:為什麼強 React 提示可以防止型別宣告錯誤啟動
Kiro 工作坊
17 與 Kiro 一起建構:建立工廠自動化入口網站 React UI
Kiro 工作坊
18 與 Kiro 一同建構:打造工廠自動化入口網站背後的自動化分析引擎
Kiro 工作坊
19 與 Kiro 一起實作:將 AI 工廠自動化輔助程式新增至工廠自動化入口網站
Kiro 工作坊
21 Kiro:2 小時專業開發人員工作坊指南
Kiro 工作坊
22 Kiro:從零建置 Fab SPC Drift Synchronization Portal
Kiro 工作坊
23 Kiro:提示詞庫與深度程式碼說明附錄
Kiro 工作坊
30 與 Kiro 一同建構:建立工廠自動化入口網站 UI
Kiro 工作坊
31 與 Kiro 一同建構:打造工廠自動化入口網站背後的自動化分析引擎
Kiro 工作坊
32 與 Kiro 一起實作:為工廠自動化入口網站增添 AI 工廠自動化助理
Kiro 工作坊
33 與 Kiro 一起開發:重建 CME Direct 風格的量化損益排行榜 UI
Kiro 工作坊
34 與 Kiro 一起開發:重建損益排行榜背後的量化分析引擎
Kiro 工作坊
35 與 Kiro 一起建構:適用於量化排行榜的 AWS AI 驅動交易台助理
Kiro 工作坊
36 單頁交易平台 SOP
Kiro 工作坊
AgentCore
A1 使用 AgentCore 與 Strands 建構:Gateway MCP 工具織網開發者工作坊
AgentCore
A2 使用 AgentCore 與 Strands 建構:受治理的多 Agent 風險系統開發者工作坊
AgentCore
A3 使用 AgentCore 與 Strands 建構:執行期主權風險代理人開發者工作坊
AgentCore
模擬考場
E1 用 Vibe Coding 打造多語言 AWS 證照模擬試題上線系統
模擬考場
E2 利用 Vibe Coding 開發技巧打造 AWS 證照模擬練習室
模擬考場
E3 打造靜態 AWS 模擬考場背後的練習引擎
模擬考場
Amazon Q
Q1 Amazon Q:ACM 憑證自動更新的CloudShell優先開發人員工作坊
Amazon Q
Tagalog 練習室
T1 為 AWS Manila Community Day 打造 Tagalog 學習 App:提示詞優先的產品設計
Tagalog 練習室
T2 為 AWS Manila Community Day 打造 Tagalog 學習 App,採用教育優先的開發提示
Tagalog 練習室
T3 為 AWS Manila Community Day 打造 Tagalog 學習 App 的開發流程深度解析
Tagalog 練習室
T4 將 Tagalog 學習 App 在 AWS Manila Community Day 情境中在地化為中文版本
Tagalog 練習室
T5 為 AWS Manila Community Day 打造 Tagalog 卡片打造文法與發音補強流程
Tagalog 練習室
T6 為 AWS Manila Community Day 打造 Tagalog 學習 App 的 Extra Examples 更獨特且可審閱
Tagalog 練習室
路線圖
R1 企業級 Data Analytics Roadmap 一百個深度情境題
路線圖
R2 前端開發路線圖:真實企業場景
路線圖
香港 Community Day
C1 伴隨 AWS Community Day 的香港週末:從雲端技術論壇到維港璀璨夜景
香港 Community Day
C2 講者的奢華週末:分享您的 AWS 故事,讓香港成為您的專屬舞台
香港 Community Day
C3 香港七十二小時:AWS Community Day 講者的極致之旅
香港 Community Day
馬尼拉 Community Day
C4 AWS Community Day Manila:一場連結雲端技術、城市文化與真摯友誼的快樂週末
馬尼拉 Community Day
C5 AWS Community Day Manila:雲端建立者在菲律賓感受最幸福的精神
馬尼拉 Community Day
C6 AWS Community Day Manila:在快樂之城建構、打破、重來,並找到歸屬
馬尼拉 Community Day
C7 菲律賓馬尼拉初次造訪建議
馬尼拉 Community Day
菲律賓 × 香港
C8 菲律賓香港資本市場升級
菲律賓 × 香港
回測
B1 使用 Bedrock AgentCore 與 Strands Agents 建立機構級 Amazon 純做多 (Long-Only) 回測代理
純做多 AMZN 代理:AgentCore、Strands 與可稽核的 Backtrader 帳本。
B2 使用 Backtrader、AgentCore 與 Strands Agents 建立具市況感知能力的 Amazon 部位管理
把市況當成部位控制,而不是圖表註解。
B3 使用 Nasdaq、S&P 500、Dow、AgentCore 與 Strands 建立相對於基準的 Amazon 進出場時機系統
相對 Nasdaq、S&P 500 與道瓊來判斷 AMZN 時機。
B4 使用 Bedrock AgentCore、Strands Agents 與 Backtrader 建立受治理的 Amazon 交易歷史工廠(Trade-History Factory)
把回測做成可稽核的交易歷史工廠。
B5 使用 Bedrock AgentCore 與 Strands Agents 建立智慧代理型 (Agentic) Amazon 回測營運模型 [Part 1]
先建立營運模型,再爭論結果。
B6 為 Amazon 擇時與部位管理建立客製化 Cerebro 程式碼說明 [第 2 部分]
先講 Cerebro 引擎,再講圖表。
B7 為 Amazon 策略結果與經驗教訓建立交易員審閱紀錄 [Part 3]
把策略排名寫成交易員審閱紀錄。
B8 使用 AgentCore 與 Strands 建立受治理的 FSI Amazon 部位管理 Playbook [Part 4]
受治理的 FSI Amazon 部位管理手冊。
B9 使用 Amazon Bedrock AgentCore 建立主權風險交易代理,分析殖利率差、FX 避險與債務重新定價
主權風險代理:殖利率差、外匯避險與債務重定價。
B11 建置現代波動率交易與合法泰國復原規劃代理程式:記憶體驅動的 Strands 多代理程式風險防護系統
記憶驅動的 Strands 代理:波動率與泰國復原規劃。
B12 使用 Amazon Bedrock AgentCore Memory 建構空頭跨式部位交易風險治理
空頭跨式部位的交易風險治理。
B13 在 Amazon EKS 上建構生產環境就緒的信用與收益質押 AI 智能體
在 EKS 上跑生產級信用與收益質押代理。
挑戰
01 週末生產力挑戰:Fab SPC 漂移同步入口網站
Fab SPC 漂移審查與建議入口網站。
02 週末生產力挑戰:Quant P&L Commander — AWS 上由 AI 驅動的交易生產力入口網站
AWS 上由 AI 驅動的交易生產力入口網站。
03 週末煩人的任務挑戰:交易台在雲端、鏈上、空中執行摘要
DeskPulse 日常交易執行摘要。
04 週末 Agent 挑戰:上午 6 點交易風險審查
無人值守、以證據為基礎的晨間交易風險簡報。
05 Weekend Creative Challenge: Leadership Card Game
瀏覽器版創意引導卡牌。
06 Full Stack Challenge: Community Day Board App
瀏覽器版活動溝通空間。
領導力卡牌
01 Leadership Card Game: 雲端還沒自動化的最後一項本事:像領導者一樣說話
寫給 建構者的現場隨筆——談語言、勇氣,以及 Leadership Card Game
02 領導力回合的解剖:Leadership Card Game 實際怎麼玩
給 建構者的引導員實地指南——讓演練嵌進真實會議
03 Leadership Card Game: 當機會不再屬於主辦者
寫給 建構者的現場隨筆:權力轉移、多語領導力練習夜,以及走完入口、資源、敘事的職涯弧線
04 週末創意挑戰:Leadership Card Game
一篇建構者手記:願景、架構,以及週末創意挑戰教會我的事
05 從週末挑戰專案到 $1,386 群眾募資:改變你在職場現身方式的領導力練習
一個週末做出的作品,變成 600 張卡的線上領導力練習室,並募到 $1,386。
06 從週末挑戰專案到 $1,386 群眾募資:進入科技產業的第一天路徑
一個週末挑戰如何變成具備 600 張卡、由 AWS 驅動的多語產品,並募到 $1,386?
07 從週末挑戰專案到 $1,386 群眾募資:用轉移機會建立專業品牌
一個週末挑戰把領導想法做成能跑的多語產品,並募到 $1,386。
08 Leadership Card Game — 群眾募資活動
募資目標: HKD 5,000 已募金額: HKD 1,386 距目標還差: HKD 3,614 進度: 28% 創作者: D.C. Dan · L.L. Diana · L.K. Lva 所在地: 日本、香港、新加坡 投資人權益: 即期價值、私密會員卡牌編輯器雲(Private Membership Card…
09 PR/FAQ 01 — Leadership Card Game 面向社群建構者正式推出
「逆向工作法」文件 · 對外新聞稿 + FAQ 產品: Leadership Card Game 受眾: 社群經理、志願組織者、職涯早期建構者
10 PR/FAQ 02 — 企業引導員採用 Leadership Card Game 進行現場領導力演練
「逆向工作法」文件 · 對外新聞稿 + FAQ 產品: Leadership Card Game 受眾: 學習與發展負責人、人員管理者、敏捷教練、企業引導員
10 PR/FAQ 03 — 多語 Leadership Card Game 為建構者擁有權開放全球練習室
「逆向工作法」文件 · 對外新聞稿 + FAQ 產品: Leadership Card Game 受眾: 全球 建構者、雙語社群、跨境產品團隊、開源導師
AWS Builder Center
01 AWS Builder Center、社群精神與 AWS Builder Jacket
霓虹訊號、共享創意,以及為建構者打造的外套。
02 走進 AWS Builder Center:一座能學習、貢獻,也讓人有歸屬感的全球技術平台
一段精彩旅程,不一定從機場開始。
03 AWS Community Builder 的巨大成功
當建構者公開分享,整個社群就會一起前進。
04 AWS Builder Center 的巨大成功
一座為好奇心打造、充滿活力的全球街區。
05 週末走進 AWS Builder Center:從社群靈感到令人難忘的 AWS Builder Jacket
星期五晚上,開始於建構者熟悉的感覺:有一個點子,正卡在問題與可能性之間。

僅供教育工程用途。本內容是軟體架構演練,不屬於製程放行建議。

步驟 7 — Render 入口網站

Kiro 提示詞

Create src/ui/render.ts and src/main.ts to render a dark engineering portal. Include summary cards, search, sort buttons, a risk board, FDC health-link cards, dynamic matching notes, yield triage notes, and runbook steps. Use assessFleet from the domain layer.

程式碼範例 — src/main.ts

import { cdSemTools, fdcHealthLinks, runbookSteps } from "./data/sampleData";
import { assessFleet } from "./domain/risk";
import { renderApp } from "./ui/render";
import "./styles.css";

const root = document.querySelector<HTMLDivElement>("#app");

if (!root) {
  throw new Error("Missing #app root element");
}

renderApp(root, {
  tools: cdSemTools,
  assessments: assessFleet(cdSemTools),
  fdcHealthLinks,
  runbookSteps
});

說明

商業邏輯: 應用程式從已知的 CD-SEM 記錄開始,計算風險評估,並將所有可供顯示的資料傳遞給 render 層。

程式碼邏輯: main.ts 刻意保持精簡。它匯入資料、呼叫領域引擎、檢查 DOM 根元素,並將 UI 建構委派給 renderApp。

預期結果: 執行 npm run dev 會顯示入口網站。如果缺少 #app,應用程式會以清楚的錯誤快速失敗。

系統設計決策

  • 進入點只負責協調。 它不應包含業務規則或複雜的 HTML。這讓產生的程式碼更容易審查,也讓應用程式的啟動路徑清楚。
  • 快速失敗的根元素驗證可避免無聲的空白畫面。 如果 HTML shell 損壞,開發人員會取得明確錯誤,而不是除錯空白頁面。這能改善工作坊的疑難排解。
  • 先計算評估,再進行 render。 UI 收到的已是解讀過的領域資料。這種分離讓風險規則能獨立於視覺版面與互動程式碼演進。

步驟 8 — 測試

Kiro 提示詞

Create tests/risk.test.ts using Vitest. Test Release, ApcGuard, HoldReview for slope, HoldReview for fleet deviation, RunGoldenWafer for residual noise, and Watch for stale blind-window conditions.

程式碼範例 — tests/risk.test.ts

import { describe, expect, it } from "vitest";
import { assessTool } from "../src/domain/risk";
import type { CdSemTool } from "../src/domain/types";

function tool(overrides: Partial<CdSemTool> = {}): CdSemTool {
  return {
    id: "CDSEM-T",
    layer: "Gate ADI",
    symptom: "baseline",
    blindWindowHours: 1,
    tmgNm: 0.1,
    mandelSlope: 1,
    fleetDeviationSigma: 0.5,
    residualThreeSigmaNm: 0.08,
    deltaMeanSeries: [0.01, 0.02],
    ...overrides
  };
}

describe("assessTool", () => {
  it("releases a healthy tool", () => {
    expect(assessTool(tool()).action).toBe("Release");
  });

  it("guards APC when TMG exceeds limit", () => {
    expect(assessTool(tool({ tmgNm: 0.25 })).action).toBe("ApcGuard");
  });

  it("requires hold review when Mandel Slope is out of range", () => {
    expect(assessTool(tool({ mandelSlope: 1.031 })).action).toBe("HoldReview");
  });

  it("requires hold review when Fleet deviation exceeds 3 sigma", () => {
    expect(assessTool(tool({ fleetDeviationSigma: 3.2 })).action).toBe("HoldReview");
  });

  it("runs golden wafer when residual noise exceeds limit", () => {
    expect(assessTool(tool({ residualThreeSigmaNm: 0.21 })).action).toBe("RunGoldenWafer");
  });

  it("watches a stale blind window", () => {
    expect(assessTool(tool({ blindWindowHours: 8 })).action).toBe("Watch");
  });
});

說明

商業邏輯: 測試將每種量測條件預期得到的建議結果編碼下來。

程式碼邏輯: Fixture factory 建立健康的預設機台,並在每個測試中覆寫一個欄位。每個斷言驗證一項特定規則。

預期結果: 當風險引擎遵循 spec 時,npm test 會通過。未來若規則變更而破壞建議行為,測試會失敗。

系統設計決策

  • 每個測試只變更一個欄位。 這能隔離因果關係,讓失敗容易理解。除非明確測試優先順序行為,否則 Kiro 產生的測試應避免混合許多無關的風險因素。
  • Fixture factory 減少重複。 開發人員可以快速新增測試,不必複製完整的機台物件。這能改善可維護性並鼓勵涵蓋更多邊界案例。
  • 測試斷言動作,而不是實作細節。 業務結果比精確的評分算術更重要。這讓內部評分能持續演進,同時保留操作行為。

步驟 9 — Hooks

Kiro 提示詞

Create .kiro/hooks/test-domain-on-save.json. Run npm test when files under src/domain or tests are saved. Also create a documentation agent hook that updates docs/decision-log.md after spec task execution.

程式碼範例 — .kiro/hooks/test-domain-on-save.json

{
  "version": "v1",
  "hooks": [
    {
      "name": "test-domain-on-save",
      "description": "Run the deterministic risk tests when domain or test files are saved.",
      "trigger": "PostFileSave",
      "matcher": "^(src/domain/.*\\.ts|tests/.*\\.ts)$",
      "action": {
        "type": "command",
        "command": "npm test"
      },
      "timeout": 60,
      "enabled": true
    }
  ]
}

說明

商業邏輯: 如果風險邏輯或測試變更,專案會立即檢查建議行為是否仍然有效。

程式碼邏輯: JSON hook 監聽符合領域或測試 TypeScript 檔案的檔案儲存事件,並執行 npm test。

預期結果: 儲存 src/domain/risk.ts 會觸發測試套件,快速顯示回歸問題。

系統設計決策

  • Hook 只鎖定高價值檔案。 每次 CSS 編輯都執行測試會浪費時間。只比對領域與測試檔案,能讓自動化保持相關且快速。
  • 動作具備決定性。 npm test 有可預期的成功或失敗輸出,因此比可能意外修改檔案的廣泛 agent action 更安全。
  • 逾時保護開發循環。 Hook 不應卡住 IDE。60 秒足以執行工作坊套件,也能教導參與者為自動化設定界限。

步驟 10 — Kiro 最終審查

Kiro 提示詞

Review the implementation against the fab-spc-portal spec. Check domain correctness, safety language, test coverage, accessibility, project structure, and hook safety. Produce a prioritized review report without modifying files.

預期的審查主題

  • 建議動作是否安全且非自主?
  • 閾值是否集中管理?
  • 風險原因是否可解釋?
  • 每項關鍵規則是否都有測試?
  • 新開發人員能否從 steering 與 spec 檔案理解專案?
  • Hooks 的範圍是否夠窄?

系統設計決策

  • 最終審查讓 Kiro 成為工程夥伴,而不是未經檢查的程式碼產生器。 開發人員要求結構化批評,再決定接受哪些發現。這能強化專業責任。
  • 不修改檔案的審查可避免意外變更。 目標是在繼續編輯前檢查涵蓋範圍與風險。這類似 pull request 審查,將分析與實作分開。
  • 審查會完成 spec 循環。 工作坊從意圖開始,最後以比較程式碼與意圖結束。這正是專業團隊應透過 Kiro 建立的核心習慣。

# 擴充 Lab:使用 Kiro 從 HTML Demo 撰寫程式碼

此擴充 Lab 保留原始建置指南,並加入來自 HTML Demo 的更多實作細節。目標是訓練開發人員使用 Kiro,將可運作的單檔 prototype 轉換為可維護的 TypeScript,同時盡可能保留 Demo 行為。

步驟 11 — 要求 Kiro 分析單體式 HTML Demo

Kiro 提示詞

Analyze the uploaded Fab SPC Drift Synchronization HTML demo. Identify all major UI sections, JavaScript data structures, functions, event handlers, CSS design tokens, and state transitions. Return a module extraction plan for a TypeScript/Vite implementation. Do not modify files yet.

預期的 Kiro 分析輸出

Kiro 應辨識出以下 Demo 元件:

  • Header 與 hero 區段。
  • 摘要統計卡片。
  • 使用 .tab 按鈕與 .portal 面板的分頁導覽。
  • 包含 CD-SEM 記錄的 tools 陣列。
  • 包含 FDC health-link 記錄的 fdc 陣列。
  • 包含專案實作步驟的 runbook 陣列。
  • 用於 FDC 卡片、runbook 步驟與 market 卡片的 renderStatic()。
  • 用於風險看板資料列的 render()。
  • 用於可展開機台詳細資訊證據面板的 panel()。
  • 用於 inline SVG 視覺化的 path()、spark() 與 fleetSvg()。
  • 用於即時時間顯示的 clock()。
  • 會變更盲窗與風險值的 setInterval() 模擬。

系統設計決策

  • 在重寫之前先做分析。 專業開發人員應要求 Kiro 先解釋並分類 prototype,再允許它產生替代程式碼。這能避免遺失原始 JavaScript 中隱藏的重要行為。
  • 輸出會成為遷移檢查清單。 每個已辨識的函式都會對應到目標模組與測試策略。這能清楚說明哪些 Demo 行為已保留,哪些行為被刻意重新設計。
  • 將模擬與 production 邏輯分離。 Demo 使用 setInterval() 變更值。在專業實作中,模擬應屬於 Demo adapter,而不是領域模型。Kiro 應將它隔離,讓測試保持決定性。

步驟 12 — 將 Demo 資料擷取為具型別記錄

Kiro 提示詞

Convert the demo's tools, fdc, and runbook arrays into typed TypeScript fixture modules. Preserve the values and labels from the HTML demo, but use camelCase fields and explicit interfaces. Put tools in src/data/tools.ts, FDC links in src/data/fdc.ts, and runbook steps in src/data/runbook.ts.

程式碼範例 — src/data/tools.ts

import type { CdSemTool } from "../domain/types";

export const cdSemTools: CdSemTool[] = [
  {
    id: "CDSEM-01",
    layer: "Gate ADI",
    symptom: "Stable master, production anchor",
    risk: 18,
    blindWindowHours: 1.2,
    tmgNm: 0.12,
    mandelSlope: 1.0,
    fleetDeviationSigma: 0.4,
    residualThreeSigmaNm: 0.08,
    action: "Release",
    deltaMeanSeries: [0.02, 0.01, 0.03, 0.01, 0.02, 0.0, 0.01, 0.02, 0.01, 0.02]
  },
  {
    id: "CDSEM-03",
    layer: "Fin dense CD",
    symptom: "Deflector DAC wobble, slope mismatch",
    risk: 91,
    blindWindowHours: 7.4,
    tmgNm: 0.23,
    mandelSlope: 1.031,
    fleetDeviationSigma: 3.2,
    residualThreeSigmaNm: 0.16,
    action: "HoldReview",
    deltaMeanSeries: [0.02, 0.03, 0.06, 0.05, 0.08, 0.12, 0.16, 0.2, 0.22, 0.24]
  },
  {
    id: "CDSEM-05",
    layer: "Contact/Via",
    symptom: "Vacuum slow degradation, residual rising",
    risk: 76,
    blindWindowHours: 6.9,
    tmgNm: 0.19,
    mandelSlope: 1.006,
    fleetDeviationSigma: 2.4,
    residualThreeSigmaNm: 0.21,
    action: "RunGoldenWafer",
    deltaMeanSeries: [0.02, 0.01, 0.04, 0.06, 0.08, 0.1, 0.12, 0.13, 0.16, 0.18]
  }
];

說明

商業邏輯: 這些記錄保留 Demo 中近似生產環境的案例:健康的母機、斜率不匹配、真空退化、殘差雜訊、Fleet 偏差與盲窗老化。

程式碼邏輯: 單體式 Demo 使用 blind、tmg、slope、fleet 與 resid 等短欄位名稱。TypeScript 版本改用 blindWindowHours、tmgNm、mandelSlope 與 residualThreeSigmaNm 等明確名稱。

預期結果: 應用程式可以 render 與 HTML Demo 相同的情境,同時讓 TypeScript 驗證每筆記錄的形狀。

系統設計決策

  • 明確欄位名稱降低認知負擔。 原始 Demo 為了簡潔使用緊湊欄位名稱。在 production-style 程式碼中,領域名稱應能自我說明,因為多位開發人員與審查者都會接觸它。
  • Fixture 資料保持接近 prototype。 保留原始值,讓開發人員能比較 TypeScript 應用程式與 HTML Demo。這使視覺與行為 parity 更容易驗證。
  • 動作以具型別值正規化。 Demo 標籤是 HOLD REVIEW 與 GOLDEN WAFER 等顯示字串。TypeScript 模型使用穩定的類似 enum 的動作值,並讓 UI formatting 處理標籤。

步驟 13 — 從 Demo 標籤新增動作標籤對應

Kiro 提示詞

Create a display mapping for advisory actions. Domain actions must be stable TypeScript values, while UI labels should match the HTML demo labels such as RELEASE, WATCH, HOLD REVIEW, GOLDEN WAFER, ROUTE LIMIT, RUN SPC, and APC GUARD.

程式碼範例 — src/domain/actions.ts

import type { AdvisoryAction } from "./types";

export const actionLabels: Record<AdvisoryAction, string> = {
  Release: "RELEASE",
  Watch: "WATCH",
  RunGoldenWafer: "GOLDEN WAFER",
  RouteLimit: "ROUTE LIMIT",
  RunSpc: "RUN SPC",
  ApcGuard: "APC GUARD",
  HoldReview: "HOLD REVIEW"
};

export function isHighAttentionAction(action: AdvisoryAction): boolean {
  return action === "ApcGuard" || action === "HoldReview";
}

export function isWatchAction(action: AdvisoryAction): boolean {
  return action === "Watch" || action === "RunSpc" || action === "RunGoldenWafer" || action === "RouteLimit";
}

說明

商業邏輯: Fab 工程師可以看到 Demo 中熟悉的標籤,而內部程式碼維持穩定的值供測試與邏輯使用。

程式碼邏輯: actionLabels 將領域動作轉換為顯示標籤。輔助函式將動作分類以供樣式使用。

預期結果: UI 輸出符合 Demo,測試也能斷言穩定的動作值,而不依賴標籤大小寫。

系統設計決策

  • 顯示文字不是領域邏輯。 標籤可能因在地化或 UX 而變更。領域值應保持穩定,讓 UI 文字變更時測試與業務規則不會中斷。
  • 樣式輔助程式避免散落字串。 沒有輔助函式時,每個 render 器可能檢查不同的標籤字串。集中管理能讓色彩與嚴重程度邏輯一致。
  • 對應表支援未來在地化。 相同的動作值可以對應到英文、繁體中文或內部 fab 術語,而不必重寫風險引擎。

步驟 14 — 將 Demo 搜尋與排序邏輯轉換為純輔助函式

Kiro 提示詞

Extract search and sort behavior from the HTML demo into pure TypeScript functions. Search should match tool id, layer, or symptom. Sort should support risk, blindWindowHours, tmgNm, mandelSlope, fleetDeviationSigma, and residualThreeSigmaNm. Add unit tests.

程式碼範例 — src/domain/filters.ts

import type { CdSemTool } from "./types";

export type ToolSortKey =
  | "risk"
  | "blindWindowHours"
  | "tmgNm"
  | "mandelSlope"
  | "fleetDeviationSigma"
  | "residualThreeSigmaNm";

export function filterTools(tools: CdSemTool[], query: string): CdSemTool[] {
  const normalized = query.trim().toLowerCase();

  if (!normalized) {
    return tools;
  }

  return tools.filter((tool) => {
    return [tool.id, tool.layer, tool.symptom]
      .join(" ")
      .toLowerCase()
      .includes(normalized);
  });
}

export function sortTools(tools: CdSemTool[], sortKey: ToolSortKey): CdSemTool[] {
  return [...tools].sort((a, b) => b[sortKey] - a[sortKey]);
}

export function filterAndSortTools(
  tools: CdSemTool[],
  query: string,
  sortKey: ToolSortKey
): CdSemTool[] {
  return sortTools(filterTools(tools, query), sortKey);
}

說明

商業邏輯: 工程師需要快速找到特定 CD-SEM、圖層或症狀,並依風險、過時的 SPC 盲窗、TMG、斜率、Fleet 偏差或殘差雜訊排列優先順序。

程式碼邏輯: filterTools 對可搜尋欄位執行不分大小寫的比對。sortTools 回傳副本而不是修改原始陣列。filterAndSortTools 組合這兩種行為。

預期結果: TypeScript 應用程式能重現 HTML Demo 的搜尋與排序行為,同時讓它們可進行單元測試。

系統設計決策

  • 篩選與排序是純領域/UI 支援函式。 它們不需要 DOM。擷取出來後可以進行單元測試,也能避免事件處理常式變成業務邏輯容器。
  • 排序回傳新陣列。 修改共用 fixture 資料可能造成令人困惑的 UI 錯誤,尤其與重複 render 結合時更是如此。不可變輸出讓狀態轉換更容易預測。
  • 搜尋欄位刻意受到限制。 比對每個屬性可能產生令人意外的結果。本工作坊選擇 id、layer 與 symptom,因為這些是工程師在 Demo 中尋找機台時會使用的欄位。

步驟 15 — 將 Demo SVG 輔助程式轉換為圖表工具

Kiro 提示詞

Extract the demo SVG path, sparkline, and fleet bar chart logic into src/ui/chart.ts. Keep the functions deterministic and return strings. Add tests for path generation with flat and increasing series.

程式碼範例 — src/ui/chart.ts

export function svgPath(values: number[], width: number, height: number, padding = 6): string {
  if (values.length === 0) {
    return "";
  }

  if (values.length === 1) {
    const x = width / 2;
    const y = height / 2;
    return `M${x.toFixed(1)} ${y.toFixed(1)}`;
  }

  const min = Math.min(...values);
  const max = Math.max(...values);
  const range = max - min || 1;
  const innerWidth = width - padding * 2;
  const innerHeight = height - padding * 2;

  return values
    .map((value, index) => {
      const x = padding + (index * innerWidth) / (values.length - 1);
      const y = padding + innerHeight - ((value - min) / range) * innerHeight;
      return `${index === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`;
    })
    .join(" ");
}

export function sparkline(values: number[], className = "line"): string {
  return `
    <svg class="spark" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
      <path class="${className}" d="${svgPath(values, 120, 32, 2)}"></path>
    </svg>
  `;
}

說明

商業邏輯: 小型圖表不需要完整的圖表函式庫,就能讓漂移趨勢可見。工程師可以看出 ΔMean 是穩定、趨勢性變化還是充滿雜訊。

程式碼邏輯: svgPath 將數值序列縮放為 SVG path 座標。sparkline 將 path 包裝在 SVG 標記中,並以 aria-hidden 標示為裝飾內容。

預期結果: 產生的 TypeScript 應用程式能重現 Demo 的 inline spark 圖表與詳細資訊面板中的大型軌跡圖。

系統設計決策

  • 圖表輔助程式回傳字串,因為應用程式不使用框架。 這讓 render 模型與 Demo 一致,也避免在兩小時工作坊中引入圖表相依套件。
  • 明確處理邊界案例。 空序列與單一點序列在天真的 path 函式中會產生無效數學運算。Kiro 應產生安全的輔助程式,因為 production 資料可能不完整。
  • 隔離 SVG 輔助程式以便測試。 重構時很容易破壞 render 數學。將它留在 chart.ts 可讓開發人員不啟動瀏覽器,也能精確測試。

步驟 16 — 將分頁切換轉換為可重用的控制器

Kiro 提示詞

Extract the demo tab switching behavior into src/ui/tabs.ts. Implement activateTab(tabId), bindTabs(container), and getActiveTab(container). Use data-tab attributes like the HTML demo. Keep it framework-free and accessible.

程式碼範例 — src/ui/tabs.ts

export function activateTab(tabId: string, root: ParentNode = document): void {
  root.querySelectorAll<HTMLElement>(".tab").forEach((button) => {
    const isActive = button.dataset.tab === tabId;
    button.classList.toggle("active", isActive);
    button.setAttribute("aria-selected", String(isActive));
  });

  root.querySelectorAll<HTMLElement>(".portal").forEach((panel) => {
    const isActive = panel.id === tabId;
    panel.classList.toggle("active", isActive);
    panel.toggleAttribute("hidden", !isActive);
  });
}

export function bindTabs(root: ParentNode = document): void {
  root.querySelectorAll<HTMLButtonElement>(".tab[data-tab]").forEach((button) => {
    button.addEventListener("click", () => {
      const tabId = button.dataset.tab;
      if (tabId) {
        activateTab(tabId, root);
      }
    });
  });
}

export function getActiveTab(root: ParentNode = document): string | undefined {
  return root.querySelector<HTMLElement>(".tab.active")?.dataset.tab;
}

說明

商業邏輯: 入口網站使用分頁區隔 overview、live risk board、FDC、matching、triage 與 runbook 工作流程。

程式碼邏輯: activateTab 切換按鈕與面板 class、設定 aria-selected,並使用 hidden 將未啟用面板從輔助技術中隱藏。bindTabs 只附加一次點擊處理常式。

預期結果: TypeScript 應用程式的行為與 Demo 相似,同時比只切換 class 更具無障礙性。

系統設計決策

  • 集中管理分頁狀態。 原始 Demo 直接在 query selector 迴圈中附加 inline 行為。控制器函式讓分頁行為可重用且可測試。
  • 同步更新 ARIA 狀態與視覺狀態。 專業 UI 程式碼不應只切換 CSS class。螢幕閱讀器需要明確的啟用狀態,未啟用面板也應隱藏。
  • 控制器維持無框架。 工作坊保留原始 Demo 的簡潔性,同時加入更好的結構與無障礙性。

步驟 17 — 轉換詳細資訊面板 render

Kiro 提示詞

Convert the demo panel(p) function into a TypeScript renderer that receives a CdSemTool and RiskAssessment. It should render status boxes, TMG vs UCL, slope, Fleet σ, residual 3σ, blind window, recommendation, evidence, SVG trajectory, and root-cause hint.

程式碼範例 — src/ui/board.ts

import type { CdSemTool, RiskAssessment } from "../domain/types";
import { actionLabels } from "../domain/actions";
import { svgPath } from "./chart";

export function renderDetailPanel(tool: CdSemTool, assessment: RiskAssessment): string {
  const trajectory = svgPath(tool.deltaMeanSeries, 680, 190, 20);

  return `
    <div class="detail" id="detail-${tool.id}">
      <div class="detail-in">
        <div class="grid2">
          <div class="chart-card">
            <div class="chart-title">
              <span>ΔMean trajectory between scheduled SPC</span>
              <span>${escapeHtml(tool.symptom)}</span>
            </div>
            <svg class="svg eq" viewBox="0 0 680 190" preserveAspectRatio="none" role="img" aria-label="${tool.id} drift trajectory">
              <line class="axis" x1="20" y1="150" x2="660" y2="150"></line>
              <line class="gridline" x1="20" y1="80" x2="660" y2="80"></line>
              <path class="fill" d="${trajectory} L 660 150 L 20 150 Z"></path>
              <path class="${assessment.score > 70 ? "line2" : "line"}" d="${trajectory}"></path>
            </svg>
          </div>
          <div class="metrics">
            <div class="chart-title"><span>Tool Health Evidence</span><span>human review required</span></div>
            <div class="metricgrid">
              ${metricBox("Status", assessment.level.toUpperCase(), assessment.level === "critical" ? "neg" : "yellow")}
              ${metricBox("Action", actionLabels[assessment.action], assessment.action === "Release" ? "pos" : "yellow")}
              ${metricBox("Score", String(assessment.score), assessment.score >= 65 ? "neg" : "pos")}
              ${metricBox("Reasons", String(assessment.reasons.length), "cyan")}
            </div>
          </div>
        </div>
        <div class="box" style="margin-top:12px">
          <div class="boxl">Root-cause hint</div>
          <div class="strategy">${escapeHtml(tool.id)} on ${escapeHtml(tool.layer)}: ${escapeHtml(tool.symptom)}.</div>
        </div>
      </div>
    </div>
  `;
}

function metricBox(label: string, value: string, tone: "pos" | "neg" | "yellow" | "cyan"): string {
  return `<div class="box"><div class="boxl">${label}</div><div class="boxv ${tone}">${value}</div></div>`;
}

function escapeHtml(value: string): string {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

說明

商業邏輯: 詳細資訊面板提供建議背後的證據:漂移軌跡、分數、動作、嚴重程度與根本原因提示。

程式碼邏輯: Render 器以具型別輸入組合 HTML。它使用 svgPath 產生圖表幾何、使用 actionLabels 產生顯示字串,並使用 escapeHtml 防止 fixture 文字變成不安全標記。

預期結果: 點擊或展開機台時,可以顯示與 HTML Demo 相似、但以模組化 TypeScript 實作的面板。

系統設計決策

  • 證據面板能提高信任。 只有風險分數並不足夠。開發人員應保留 Demo 的詳細資訊面板概念,因為它能解釋建議的原因。
  • 在遷移期間加入 escaping。 原始 Demo 控制所有字串,但專業程式碼不應假設未來的資料永遠安全。Escaping 能防止意外的 HTML injection。
  • 圖表 render 保持輕量。 面板以不使用外部相依套件的方式重現 prototype 的 SVG 方法。這適合本機 Kiro 工作坊,也讓程式碼審查保持可控。

步驟 18 — 以決定性 Demo 模式取代即時亂數變更

Kiro 提示詞

The HTML demo uses setInterval and Math.random to mutate risk values. Replace this with an optional deterministic demo ticker that accepts a seeded sequence of deltas. Keep production state immutable and tests deterministic.

程式碼範例 — src/domain/demoTicker.ts

import type { CdSemTool } from "./types";

export function applyDemoTick(tools: CdSemTool[], deltas: number[]): CdSemTool[] {
  return tools.map((tool, index) => {
    const delta = deltas[index % deltas.length] ?? 0;
    const nextBlindWindowHours = Math.max(0, round(tool.blindWindowHours + 0.02));
    const nextRisk = Math.max(0, Math.min(100, Math.round(tool.risk + delta)));
    const lastDeltaMean = tool.deltaMeanSeries.at(-1) ?? 0;

    return {
      ...tool,
      blindWindowHours: nextBlindWindowHours,
      risk: nextRisk,
      deltaMeanSeries: [...tool.deltaMeanSeries.slice(1), round(Math.max(0, lastDeltaMean + delta / 1000))]
    };
  });
}

function round(value: number): number {
  return Number(value.toFixed(3));
}

說明

商業邏輯: Demo 仍可以顯示隨時間變動的值,但變更對測試與示範而言是可預測的。

程式碼邏輯: applyDemoTick 回傳含有更新後盲窗持續時間、風險與時間序列資料的新陣列。它不會修改原始機台。

預期結果: 開發人員可以示範類似即時的行為,同時讓單元測試保持穩定。

系統設計決策

  • 從核心邏輯移除亂數。 原始 Demo 使用 Math.random() 製造視覺變動。專業程式碼應隔離亂數,讓測試與審查不依賴非決定性行為。
  • 不可變更新簡化 render。 回傳新物件讓狀態變更更容易推理,也能防止模組之間的隱藏修改。
  • 明確標示 Demo 模式。 Ticker 對工作坊很有用,但不應看起來像真正的遙測資料。命名為 demoTicker 可以避免與 production ingestion 混淆。

步驟 19 — 為 HTML Demo 衍生的輔助程式新增測試

Kiro 提示詞

Generate tests for the helper functions extracted from the HTML demo: filterTools, sortTools, svgPath, applyDemoTick, action label mapping, and risk priority. Include edge cases for empty query, unknown query, flat series, single-point series, and immutable updates.

程式碼範例 — tests/demoHelpers.test.ts

import { describe, expect, it } from "vitest";
import { filterTools, sortTools } from "../src/domain/filters";
import { applyDemoTick } from "../src/domain/demoTicker";
import { svgPath } from "../src/ui/chart";
import { cdSemTools } from "../src/data/tools";

describe("demo-derived helpers", () => {
  it("filters by layer or symptom", () => {
    expect(filterTools(cdSemTools, "deflector")).toHaveLength(1);
    expect(filterTools(cdSemTools, "gate").length).toBeGreaterThan(0);
  });

  it("returns all tools for empty search", () => {
    expect(filterTools(cdSemTools, "")).toHaveLength(cdSemTools.length);
  });

  it("sorts without mutating the original array", () => {
    const before = cdSemTools.map((tool) => tool.id).join(",");
    const sorted = sortTools(cdSemTools, "risk");
    const after = cdSemTools.map((tool) => tool.id).join(",");

    expect(sorted[0].risk).toBeGreaterThanOrEqual(sorted.at(-1)?.risk ?? 0);
    expect(after).toBe(before);
  });

  it("creates an SVG path for a flat series", () => {
    expect(svgPath([1, 1, 1], 120, 32, 2)).toContain("M");
  });

  it("applies deterministic demo ticks immutably", () => {
    const updated = applyDemoTick(cdSemTools, [1, -1]);

    expect(updated).not.toBe(cdSemTools);
    expect(updated[0]).not.toBe(cdSemTools[0]);
    expect(updated[0].blindWindowHours).toBeGreaterThan(cdSemTools[0].blindWindowHours);
  });
});

說明

商業邏輯: 測試驗證 HTML Demo 衍生的行為,在變得更安全且更可維護的同時仍被保留。

程式碼邏輯: 測試套件檢查篩選、排序、SVG path 建立與決定性狀態更新,也驗證不可變性。

預期結果: Kiro 重構 render 或狀態邏輯時,這些測試會捕捉意外的行為回歸。

系統設計決策

  • 輔助程式測試保護擷取出的行為。 從 HTML 遷移至 TypeScript 可能細微破壞排序、篩選或圖表。這些測試保護 Demo 的核心互動。
  • 不可變性測試防止隱藏耦合。 在精簡 Demo 中,修改資料或許可以接受,但在較大型的應用程式中會產生缺陷。測試不可變性會迫使狀態管理更乾淨。
  • 圖表測試關注有效性,而不是像素。 SVG path 測試應確保邊界案例的輸出格式正確。像素級 render 應由視覺審查處理,而非單元測試。

步驟 20 — 要求 Kiro 產生 Demo parity 檢查清單

Kiro 提示詞

Create a demo parity checklist comparing the TypeScript implementation against the original HTML demo. Include sections for layout, navigation, data, risk board, detail panel, FDC cards, runbook, charts, responsive behavior, and safety language.

預期的檢查清單

# Demo Parity Checklist

## Layout
- [ ] Header contains AWS logo block and live status.
- [ ] Hero contains SPC Frequency / Mass Production Sync message.
- [ ] Summary cards show tools watched, blind window, Fleet OOC risk, FDC links, dynamic limits, yield watch lots.

## Navigation
- [ ] Tabs switch active panel without page reload.
- [ ] Active tab state is visually clear.
- [ ] Inactive panels are hidden from assistive technology.

## Risk Board
- [ ] Search matches tool id, layer, and symptom.
- [ ] Sort works for risk, blind window, TMG, slope, Fleet σ, and residual.
- [ ] Detail panels show evidence and trajectory.

## Safety
- [ ] No button issues real equipment commands.
- [ ] Footer states advisory-only behavior.
- [ ] APC Guard is represented as review guidance, not an automated APC write.

系統設計決策

  • Parity 檢查清單防止意外縮減範圍。 Kiro 將程式碼模組化時,可能遺漏 prototype 中小而重要的行為。檢查清單提供簡明的驗證工具。
  • 安全有自己的檢查清單區段。 此入口網站的領域需要明確的僅供建議語言。將安全視為獨立審查區域,能更難漏掉它。
  • 無障礙功能改善原始 Demo。 Parity 不代表複製每項限制。TypeScript 實作應保留行為,同時改善 ARIA 狀態與鍵盤操作性。