搜尋開發指南

試試「多租戶」、「啟動」或「outbox」。
搜尋僅使用本站文件,不會傳送至外部服務。

文件目錄

NEXUSPRO / HANDBOOK

工作紀錄與待辦

了解本人 worklog、月度 summary、todo、冪等 request key、樂觀版本與 workflow task 頁面的資料契約。

內容核對 2026-09-28·圖文指南

本章目標與前置條件

讀完後,你應能實作或驗證本人工作紀錄與個人待辦,理解 owner scope、client request id、optimistic version,以及為何月度 summary 不能由前端拼接分頁資料。前置條件是熟悉 ISO month、分頁、JSON closed object 與 409 conflict。

功能現況

區塊後端已核實能力前端現況
Worklog optionscategories、products(key 與 label 都是 service 內的常數詞彙)、duration_step_minutes(30)、daily_target_minutes(420,僅為顯示目標,不限制填寫)readWorklogOptions 載入建立表單選項與頁首的時數說明
Worklog entriesmonth list、create、summary、update、delete;create 必填 client_request_id,且帳號需有 employee associationfeatures/worklog/api.ts 與 features/worklog/useWorklog.ts 提供讀寫與快照確認;列表以 fetchAllPages 讀完整月(每頁 100),UI 不分頁
Todolist、create、update、delete;可用 done=true/false 篩選;create 同樣必填 client_request_id,不需要 employeetasks 頁面/TodoList 讀取全部 todo(含已完成)並顯示完成狀態
冪等與版本同 body request key replay 201;不同 body 或原資源已刪除 409/10801;stale base_version 409/10800hook 對 uncertain POST 重試同 UUID,讀回後要求明確 acknowledge
Summary回傳該月每個 Gregorian day(含 0 activity)與完整統計月合計與每日合計都取自 summary,不從列表 rows 自己加總
範圍只有 /v1/me/**;部門彙總、代填、核准不在本次範圍/tasks(page workflow.task)依 worklog.entry.read、worklog.todo.read 分別顯示兩個區塊,沒有 fixture 模式

容易混淆的相鄰資料:GET /v1/workspace/overview/todos 屬於 HR 工作區總覽(hr.workspace_todo),與個人待辦無關;features/work-hours 的 WorkHoursPanel(/workspace/attendance)讀的是 /v1/attendance/days 出勤資料,也不是 worklog。

核心概念

「我」由 authentication 決定

API 以 /me 命名只是提醒 scope 來源,不是讓 client 傳 account_id。每條 SQL 都同時限定 tenant_id 與 owner_account_id,RLS 只是資料庫後備。只有 worklog create 會 resolve authenticated account 的 employee association 並寫入 employee_id;沒有 employee association 回 422 10802 worklog_employee_required。list、summary、update、delete 與所有 todo 操作都不查 employee。所有 read/write 都在 tenant context 內進行。

request key 與版本各自解決不同問題

client_request_id(entry 與 todo create 都必填,須為非零 UUID)解決網路重試造成的重複 create:相同 normalized body 回原 201;不同 body,或原本建立的資源已被刪除,回 409 10801 worklog_request_conflict。base_version 解決兩個畫面同時編輯:update 放在 body,delete 放在 query(?base_version=);舊版本回 409 10800 worklog_version_conflict,呼叫端必須重讀後再決定是否覆寫。update 是全量替換,所有可編輯欄位都要送,nullable 欄位要明確送 null;delete 成功回 200 與 {id, deleted: true}。

Summary 是完整月度讀模型

list API 必須傳 month(YYYY-MM,年份 2000–2100),以 work_date DESC, created_at DESC, id DESC 排序並分頁(sort 只接受 -work_date,page_size 最大 100);summary API 則一次回傳該月所有日,包含沒有 activity 的日子,並附 daily_target_minutes。月度總計不可用一頁資料或 UI 當前顯示列推導;前端雖以 fetchAllPages 讀完整月列表,合計仍只取 summary。

Todo 狀態有時間語意

todo create 的 done=false、completed_at=null 由 server 初始化。false → true 會寫入一次完成時間;true → false 會清除;持續 true 不刷新 timestamp。UI 需保留 completed item,不能將完成項誤當不存在。list 依 created_at DESC, id DESC 排序(sort 只接受 -created_at),不帶 done 時回傳全部。

欄位驗證規則

  • entry:name trim 後 1–200 個 Unicode 字元;work_date 為 2000-01-01 至 2100-12-31 之間的實際日期;category 限 design、meeting、discussion、development、testing、research、other;product 可為 null,否則限 ai_product、nexus、koir、other;duration_minutes 為 30–1440 且是 30 的倍數;note 可為 null,trim 後為空視同 null,最多 2000 字。
  • todo:text trim 後 1–500 字;due_date 可為 null,否則套用相同的日期範圍。
  • body 是 closed object:product、note、due_date 必須出現(可為 null),未知欄位與型別錯誤都以 422/10430 field errors 回報。
  • 前端 payload schema 使用 .strict(),送出前就擋下未知欄位;response schema 使用 .passthrough()。

一條請求鏈

架構流程圖 · Mermaid

正在繪製架構圖…

查看圖表原始碼
flowchart LR
  Tasks["TasksPageContent"] --> Options["GET /v1/me/worklog-options"]
  Tasks --> Entries["/v1/me/worklogs"]
  Tasks --> Summary["GET /v1/me/worklogs/summary"]
  Tasks --> Todos["/v1/me/todos"]
  Entries --> Owner["authenticated account(owner_account_id)"]
  Summary --> Owner
  Todos --> Owner
  Entries -.->|"僅 create"| Employee["employee association"]
  Owner --> Tx[("tenant transaction + audit")]

frontend 的 fetcher/mutator 依 schema 解析結果。SWR key 依資源類型區分:entries 與 summary 為 ['worklog', identity, 'entries', month]、['worklog', identity, 'summary', month],options 與 todos 不帶 month;TasksPageContent 另以 tenant:account 為 key 包一層獨立 cache 的 SWRConfig,換帳號即重建。mutation 成功後刷新受影響月份的 entries 與 summary(改日期跨月時兩個月都刷新)或 todos;不確定的結果(無回應、5xx 或 response schema 不符)先讀回,再由使用者確認 snapshot,避免無聲覆蓋。

實作步驟與示例

  1. 先讀 api/openapi.yaml 的 Worklog schemas、month/done query 與 conflict codes,再讀 handler request decoder;route policy(worklog.entry.*、worklog.todo.*、page workflow.task、delete 為 high risk)以 internal/route/testdata/registry.golden 為準。
  2. 新增 entry 欄位時同步 domain validation、JSON codec、request closed object、service、OpenAPI、frontend schema 與 contract test。
  3. create 使用每次操作唯一 client_request_id,retry 必須重送相同 body;update 在 body、delete 在 query 帶最新 base_version。
  4. UI 顯示月摘要時直接使用 summary days/totals,列表只負責列出項目;遇到 409 要保留本地編輯並引導 re-read。
http
GET /v1/me/worklogs?month=2026-09&page=1&page_size=20&sort=-work_date
GET /v1/me/worklogs/summary?month=2026-09
GET /v1/me/todos?done=false&page=1&page_size=20
DELETE /v1/me/todos/:todoId?base_version=3

正式 create/update body 以 OpenAPI WorklogEntryCreateRequest、WorklogEntryUpdateRequest、PersonalTodoCreateRequest、PersonalTodoUpdateRequest 為準;不在文件內填人員、專案或憑證值。驗證要覆蓋沒有 employee、相同 key replay、改 body conflict、stale version 與 completed_at 轉換。

驗證矩陣

驗證問題程式碼/測試證據仍需另外做的驗收
closed body/field validationinternal/api/v1/worklog_test.go、internal/service/worklog/validation_test.go、features/worklog/api.contract.test.tslive API 欄位錯誤與 payload size
owner scope/month paginginternal/service/worklog/service_test.go、tests/integration/postgres/worklog_repository_test.go、worklog_service_real_test.go、E2E tests/e2e/worklog_routes_test.go(管理員也不能經 /me 覆寫他人資料)、features/worklog/useWorklog.test.tsx部署環境的 employee link 與跨租戶負向案例
idempotent createinternal/service/worklog/service_test.go、tests/integration/postgres/worklog_concurrency_test.go、features/worklog/useWorklog.test.tsxnetwork timeout 後真實重試與 readback
optimistic update/deleteinternal/service/worklog/service_test.go、tests/integration/postgres/worklog_concurrency_test.go、features/worklog/api.contract.test.ts兩瀏覽器/兩 session 競態
summary/todo semanticsinternal/service/worklog/calendar_test.go、internal/service/worklog/service_test.go、features/worklog/api.contract.test.ts月末、閏年與部署時區

常見錯誤

  • create retry 產生新 client_request_id,造成一個使用者動作寫入兩筆。
  • 收到 409 version conflict 仍直接重送舊 payload,覆蓋掉別人的最新版本。
  • 用列表 page 的 rows 相加當月總計,漏掉其他 page 與 0 activity days。
  • 把 todo done=true 直接移除,造成 completed item 無法查回或反映完成時間。
  • 以為 todo 也需要 employee 綁定,或因為 todo 能用就認定可以建立 worklog;只有 worklog create 需要 employee(422/10802)。
  • 把 WorkHoursPanel(出勤工時)或 /v1/workspace/overview/todos(HR 工作區)當成 worklog 或個人待辦的資料來源。
  • 把前端 useWorklog 測試或 contract test 成功當成部署 acceptance;worklog 前端沒有 fixture 模式,本文沒有執行正式 API 或使用真實帳號。

相關文件

內容來源與核實範圍

以下路徑相對於所列業務倉庫;核實層級為「已讀原始碼」,不是本輪業務測試或部署驗收。

  • nexus-pro-be-plus/internal/api/v1/worklog_routes.go
  • nexus-pro-be-plus/internal/api/v1/worklog_requests.go
  • nexus-pro-be-plus/internal/service/worklog/entries.go
  • nexus-pro-be-plus/internal/service/worklog/codec.go
  • nexus-pro-be-plus/internal/service/worklog/ports.go
  • nexus-pro-be-plus/internal/domain/worklog/entry.go
  • nexus-pro-web-plus/features/worklog/api.ts
  • nexus-pro-web-plus/features/worklog/useWorklog.ts
  • nexus-pro-web-plus/features/worklog/useWorklog.test.tsx
  • nexus-pro-web-plus/app/(platform)/tasks/_components/TasksPageContent.tsx
  • nexus-pro-web-plus/app/(platform)/tasks/_components/TodoList.tsx
  • nexus-pro-be-plus/internal/service/worklog/todos.go
  • nexus-pro-be-plus/internal/api/v1/worklog_handlers.go
  • nexus-pro-be-plus/db/queries/worklog.sql
  • nexus-pro-be-plus/tests/integration/postgres/worklog_concurrency_test.go
  • nexus-pro-be-plus/tests/e2e/worklog_routes_test.go
  • nexus-pro-be-plus/docs/plans/2026-09-20-worklog-todos.md
  • nexus-pro-web-plus/features/work-hours/api.ts
NexusPro 開發指南以程式碼為準 · 以驗證為據