座標:精確的笛卡兒與地理位置
儲存什麼
coordinate 在 record.data 內嵌儲存完整的精確小數向量。倉庫/儲位或設備位置選 cartesian,WGS84 經緯度則選 geographic。每個分量都是小數字串,不是 JavaScript Number;每軸的 precision 與 scale 沿用既有定點小數規則。
非必填 cell 可整格為 null,但非 null 值必須包含全部宣告軸。它不是可以任意加欄的 JSON、地圖顯示元件,或指向據點紀錄的 link。
建立笛卡兒欄位
以下是 columns.create 的 body;scope 與 table ID 由端點路徑提供:
{
"name": "Bin position",
"type": "coordinate",
"coordinate_system": "cartesian",
"axes": [
{"key": "x", "label": "Aisle axis", "precision": 12, "scale": 3, "min": "0", "max": "1000"},
{"key": "y", "precision": 12, "scale": 3},
{"key": "z", "precision": 12, "scale": 3}
],
"length_unit": {"kind": "uom", "fixed": "m"}
}笛卡兒設定要求 1–8 個有序軸。key 必須不重複且符合 [a-z][a-z0-9_]{0,31}。每軸必填整數 precision(1–38)與 scale(0–18,且不得超過 precision);可選 label 最多 128 字元,min/max 則是純小數字串。min 不得大於 max。
length_unit 可省略,只適用於笛卡兒。它沿用單位選擇器:kind: "uom",fixed 與 unit_column 必須恰好擇一。Selector 不是自動換算。Column compatibility 檢查 dimension,per-row selector 求值前須解析為相容的實際 unit。缺少/隱藏 selector 或 actual unit 不同都拒絕,即使軸值看起來相同。
可寫物件,或依宣告軸順序寫笛卡兒陣列:
{"data":{"Bin position":{"x":"12.500","y":"3.250","z":"0.000"}}}{"data":{"Bin position":["12.500","3.250","0.000"]}}兩種都正規化成軸鍵物件。陣列長度必須完全相符,不要用物件鍵的插入順序改變軸順序。
建立地理欄位
{
"name": "Location",
"type": "coordinate",
"coordinate_system": "geographic"
}省略 axes 時產生依序的 lat、lon,兩者都是 precision 10、scale 7。明訂地理軸時必須依序是 lat, lon 或 lat, lon, alt,每軸仍要提供 precision 與 scale,不會自動新增第三軸。海拔以公尺為單位,不是另一個類似經度的軸。
- 緯度接受 −90 至 +90,含邊界。
- 經度接受 −180 至 +180;+180 會正規化為 −180。
- 明訂每軸界線可縮小範圍,不能取消地理範圍驗證。
- 地理值只能是物件,不能用笛卡兒陣列。地理欄不能設定
length_unit;笛卡兒欄不能帶擷取 metadata。
一般非擷取 REST 輸入:
{"data":{"Location":{"lat":"25.0339640","lon":"121.5644680"}}}正規化後的地理 cell:
{
"lat": "25.0339640",
"lon": "121.5644680",
"src": "client",
"acc_m": null,
"at": null
}src 由伺服器寫入 context 指派,不信任輸入 cell 的聲明。輸入別名是 accuracy_m/acc_m 與 captured_at/at;儲存使用 acc_m、at。有精度值時必須是非負純小數字串。擷取時間必須是帶時區的 ISO-8601,正規化成 UTC。任意多餘鍵或不完整座標會被拒絕。
擷取設定不是身分驗證
地理欄接受以下設定物件:
{
"name": "Check-in location",
"type": "coordinate",
"coordinate_system": "geographic",
"capture": {"capture": true, "accuracy": true, "source": true, "captured_at": true}
}四個旗標都是嚴格 boolean。預設 capture: false,其他三個為 true。這些旗標不是讀取授權,也不能讓用戶端提供的 src 變成可信來源。
Capture provenance 依 ingress 預設拒絕:只有登入還不夠。Explicit marker 僅包住明訂 capture field 的單次正規化,並在 finally 重設,不能傳至 nested write 或 background work。Manual Command capture input 與單筆 private REST capture field 另需互動式非 service JWT、相同 acting tenant/user。Device reading 必須同時有 accuracy_m、captured_at,accuracy 為正,未來誤差最多五秒。見 ingress → source 表與運算子 capture 邊界。
明訂的互動式 capture 缺少任一 metadata field(包括兩者皆缺)都會拒絕,不會默默退回 client。一般非 capture 的 client 座標仍受支援;stored-evidence replay 不會更新 capture provenance。
匯入永遠不得取得 device provenance,不論檔案帶何種 evidence key。Import v1/v2 為 import、IaC 為 iac;bulk/batch/mass update、duplicate、public/anonymous、Agent/MCP、服務/API key、Sandbox、EdgeWorker 寫入為 client。Derived write 為 command:<id> 或 client,不繼承 capture authority;undo/restore/history replay 原樣保留 stored src、acc_m、at。此 pin 已含 source fix,owner E2E 驗收仍待完成。
通過登入的 Geolocation reading 仍不是裝置驗證:被偽造的裝置可以說謊。幾何與回報品質可檢查,實際人在現場並沒有被獨立證明。
IaC、匯入與 schema 演進
IaC passthrough 保留 coordinate_system、axes、length_unit、capture;length_unit.unit_column 以本表 column ref 作 forward/reverse translation。IaC record 使用原生軸鍵 object(Cartesian 也可 ordered array),不是 JSON-encoded/comma 字串。地理 IaC 寫入標記 src: "iac",import v1/v2 為 src: "import"。檔案 accuracy/time 仍是 untrusted import data,不是 device-capture 證據。座標不能作 IaC natural key 或 upsert match_column。
檔案交換
CSV/XLSX export 依 declared axis order 展開 <display-column-name>.<axis-key>,不是 axis label。Geographic 預設 lat、lon;若宣告 alt,每個非 null point 都需要它。輸出 decimal 字串(XLSX text cell),省略 src、acc_m、at、unit metadata、capture config;axis-only file 不是 provenance round-trip。
既有 schema mapping 可用 Location.lat/Location.lon 等 per-axis target,或整個 point 的 text cell,內含 components 帶引號的 JSON。Cartesian JSON array 依 declared axis order。恰好兩個 comma 分量表示 geographic lat,lon,沒有 altitude/Cartesian comma 簡寫。空白整個 point text 是 null;不完整 vector 拒絕。
Mapped coordinate source 需 CSV text,或 XLSX preserve_text_cells=true 且來源是 authored text cell。Numeric/formula-derived cell 與 .xls 都不通過 exact-source guard。Create-from-file 不會把數個 exported axis 欄位合成 coordinate,應先宣告 schema 再 mapping。
此 pin 的 legacy queued dotted-axis XLSX import 因 worker binding 不符(col_….lat 與 schema-column key)在 insert 前拒絕;row mapper/export renderer 不代表路徑已通過 E2E。Coordinate reseeding 作 literal 比較,scale/array/provenance 正規化差異可形成 drift,而非 no-op。
- 建立後
coordinate_system、有序軸 key 與length_unit不可變。 - 修改 precision/scale/bounds 會驗證既有資料,受 10,000 筆 migration 上限約束。不相容值會拒絕變更,不代表可悄悄四捨五入或丟掉分量。這類變更在儲存超過 500 筆紀錄(含垃圾桶中的)的表上,會讓座標索引維持待處理。新增座標欄若是同步進行,也一樣:IaC 與 Agent 工具箱的新增一律同步,REST 新增在不超過 500 筆 live 紀錄時預設也是同步。以 REST 對超過 10,000 筆 live 紀錄的表新增座標欄,同樣讓索引維持待處理。待處理的索引會一直如此,直到 operator 回填為止。
- 拒絕與其他型別互轉,唯一例外是座標 → JSON,保留原物件。
default_value、max_length、options不是座標設定欄位。
型別註冊錯誤與查詢限制
以下是正規化/設定層的 code,不代表所有公開介面都使用相同 HTTP status 或 envelope:
| Code | 意義 |
|---|---|
ct.coordinate_system_invalid | 缺少或不支援的 system |
ct.coordinate_axes_required/ct.coordinate_axes_invalid | 缺少笛卡兒軸、非法順序/key/數量,或不支援的地理軸 |
ct.coordinate_axis_config_invalid/ct.coordinate_bounds_invalid | 非法軸設定或範圍違規 |
ct.coordinate_incomplete/ct.coordinate_axes_mismatch | 缺少分量、陣列長度不符或未知鍵 |
ct.coordinate_value_invalid/ct.coordinate_component_invalid | 值形狀或小數分量錯誤 |
ct.coordinate_capture_invalid/ct.coordinate_unit_invalid | 擷取/單位設定不適用於此 system |
ct.coordinate_accuracy_invalid/ct.coordinate_capture_time_invalid | 精度或帶時區擷取時間錯誤 |
ct.coordinate_capture_incomplete/ct.coordinate_capture_future | 擷取缺少證據或超過未來容許誤差 |
ct.coordinate_schema_data_conflict/ct.coordinate_migration_cap | 既有資料阻擋 schema 變更或掃描超過上限 |
ct.coordinate_config_immutable/ct.coordinate_unit_immutable/ct.coordinate_retype_refused | 要求修改不可變設定或禁止的型別轉換 |
ct.coordinate_sql_unsupported | 要求不支援的純量座標篩選/排序 |
在 stored_filters 與 any_of 中對座標 cell 做純量比較,以及對座標欄使用一般的 sort_by key,或在沒有 distance_from key 的 sort 中使用一般的 sort key,都會以 ct.coordinate_sql_unsupported 拒絕;presence 另行處理。舊版 filters map 不檢查座標欄,所以不要用它篩選座標欄。空間查詢篩選(within、within_any)與距離排序是自 backend 5.21.0 起的獨立具型別運算子;請求形狀、持久化索引與上限見座標查詢。另請見幾何、運算子與出勤 how-to。一般欄位 ACL保護精確位置;capture 旗標不會隱藏個資。