技術細節

ICT Setter 的構造,供負責運行的 IT 人員,以及想了解由輸入題目到列印試卷之間發生甚麼事的人參考。

技術組合

部分 技術
介面 React 19、TypeScript 及 Vite;Fluent UI 及 Base UI 組件,配上套件自家的藍綠色主題
伺服器 Node.js、Express 及以 SQLite 為基礎的 Prisma,連線階段儲存在數據庫
文件 以 Python 填寫已審批的 Word 範本,再由 LibreOffice 轉換為 PDF
圖表 XeLaTeX 配合 TikZ,再以 dvisvgm 及 Poppler 輸出 SVG 及 PNG
答案檢查器 Python,並以 g++ 及 Free Pascal 處理 C++ 及 Pascal 答案

單一程式庫

packages/exam-core            試卷的定義:試卷模型、編解碼及驗證
packages/publication-contracts  列印及匯出請求的定義
packages/assessment-domain     考試規則:流程、鎖定、成績及分析
apps/assessment-server         Assessment 的用例及 API
apps/assessment-client         Assessment 的介面
shared/                        編輯、協作及題庫
server/                        提供兩個應用程式的伺服器及背景程序
client/                        ICT Setter 的介面
scripts/                       文件排版、TikZ 編譯器、答案檢查器
site/                          本網站

Assessment 從不引用擬卷部分的程式碼;邊界測試及 lint 規則確保這一點,因此考試部分只依賴試卷模型及自身的規則。

試卷模型

一份試卷是一個樹狀結構:分部、題目、分題及子題,以及其中的組件(文字、列表、表格、程式碼、圖片、圖表、答題空間、分頁)。每段文字都是中英文一對,採用一種精簡的富文字格式,可標示粗體、斜體、程式碼、底線、上標及加框空格。同一套編解碼及驗證在編輯器中(即時)及伺服器上(儲存前)運行。

每個節點都有穩定的識別碼,試卷會序列化為標準 JSON,作為雜湊的依據。修改以針對指定版本的操作傳送;同一時間只限一人編輯,編輯期間租用權會自動續期,而每個已儲存的版本都會保留。

由試卷到列印

  1. 試卷先轉為排版計劃:題號、分部標題、分頁及答題空間,一次計算,供中英文共用。
  2. Python 排版程式開啟已審批的 Word 範本,把試卷內容填入標記的區域,因此頁首、頁尾、封面及版面設定都直接來自範本。
  3. LibreOffice 把 Word 檔轉換為 PDF,用於預覽及列印。

範本以範本套件提供,經內容雜湊並須由管理員批准後才可使用。工作在背景程序執行,每項工作都會報告進度,讓介面顯示正在進行的步驟。

中文排版依循固定規則:內文用新細明體,粗體用華康儷粗黑,中文字加 1 點字距,英文字母及數字則不加。排版程式以試卷字型的實際字寬量度文字,用以把分數放在最後一行末端,並按內容調整表格及程式碼的闊度。

圖表

擬卷人只需撰寫繪圖指令,文件設定、字型及程式庫都已固定。可讀寫檔案、定義巨集或連接網絡的指令會在編譯前被拒絕。每個圖表的編譯都有時間及輸出上限,SVG 在儲存前只保留基本圖形。結果按原始碼、標籤及工具版本的雜湊值快取,未改動的圖表不會重複繪製。

考試

  • 每個考試鎖定一個已鎖定的試卷版本及一個評卷參考版本,並記錄兩者及每張圖片的雜湊值。由派發試卷至報告,考試的每個步驟都經此鎖定讀取並加以核對。
  • 考生收到的是試卷的白名單投影:題目、內容及以穩定識別碼標示的選項,絕不包括評卷參考、備註或出處。
  • 由伺服器計時。已提交的答案由數據庫觸發器凍結,完成的批改亦不會再被修改:重新批改會新增一輪批改。
  • 總分、等級、排名及統計都在讀取時由分數計算,從不儲存,因此不會與批改結果出現偏差。
  • 每個計分分題都有等同性雜湊值,只有真正相同的分題才會跨考試合併統計。

答案檢查器

閱卷員的檢查程式以 Python 撰寫,不論考生用哪種語言作答。檢查程式設定輸入、執行答案、呼叫函數並列明預期結果;同一程式可用於 Python、Pascal 或 C++ 答案、SQL 語句或試算表公式。只寫了程式片段或把數據直接寫在程式中的答案,亦會按原樣處理。

考生的程式在獨立程序中執行,不繼承環境變數,只有自己的空白資料夾,並設有 5 秒時間上限、記憶體上限,以及檔案和輸出大小上限。

保安

  • 職員帳戶只限邀請;連線階段儲存在伺服器。
  • 會改動資料的請求都附有 CSRF 權杖。
  • 考生密碼只顯示一次,並只以 scrypt 雜湊值儲存。考生的連線 cookie 設為 httpOnly 及 SameSite=Strict,只限考試 API 使用,登入亦有次數限制。
  • 沒有考試角色的職員不會看到該考試;角色欠缺的權限會被拒絕。

測試

每個套件都有自己的 Vitest 測試;排版程式、TikZ 編譯器及答案檢查器以 pytest 測試;Playwright 則端對端操作兩個應用程式,包括考生應考的過程。持續整合會檢查格式、lint、型別及所有測試,在 Linux 上產生文件,並在 Windows 上測試 Windows 部署指令碼。