object-record
Skill13 starsChanged 33 days agoMITView on GitHub
Quản lý bản ghi Cogover Object qua Records API `/bapi/v1/records` (lấy danh sách có lọc/phân trang, đếm và thống kê theo nhóm, tạo, cập nhật, xoá) và upload/gắn file, chèn ảnh local vào long-text WYSIWYG bằng phiên Web App. Dùng khi cần thao tác record, tạo record kèm file hoặc ảnh trong cùng request, hoặc đính kèm file vào record hiện có; xoá phải xác nhận trước.
In this repository23 other files it gives its agents.
- agent-builderSkill
- app-menu-managerSkill
- build-cogover-appSkill
- cogover-api-authSkill
- cogover-custom-moduleSkill
- cogover-iconSkill
- cogover-overviewSkill
- create-cogover-objectsSkill
- dashboard-builderSkill
- document-templateSkill
- layout-scriptingSkill
- object-buttonSkill
- object-filterSkill
- object-formSkill
- object-history-trackingSkill
- object-infoSkill
- object-layoutSkill
- object-path-componentSkill
- object-transition-ruleSkill
- process-creatorSkill
- record-emailSkill
- report-builderSkill
- user-permissionSkill
The file
Files
Object Record
- Phiên bản:
1.3.0 - Ngày phát hành:
2026-10-21
Sub-agent thao tác bản ghi (record) của một Cogover Object; skill khác gọi skill này khi cần đọc/ghi record. Credential, header và quy ước response/lỗi chung: theo $cogover-api-auth. Các API record dùng /bapi/v1 với API Key Bearer; riêng upload file và gắn file vào record đã tồn tại dùng /api/v1 bằng phiên Web App (đổi từ API Key qua $cogover-api-auth; không tạo được phiên thì dừng và báo người dùng, không gọi /api/v1 bằng API Key).
Chuẩn bị
- Object ID,
object_slugvà fields của Object: lấy qua$object-infonếu chưa có. Với field file luôn lấyslug,fieldTypevàmultipletừ metadata; không suy đoán từ tên hiển thị. - Upload file/ảnh WYSIWYG: cần đường dẫn tuyệt đối tới file (tồn tại, không rỗng), metadata field đích và phiên Web App; chỉ cần ID bản ghi khi gắn vào record đã tồn tại.
- Các khả năng A–F độc lập, không cần gọi theo thứ tự.
A. Lấy danh sách — POST /bapi/v1/records/list
{
"object_slug": "{OBJECT_SLUG}",
"type": {TYPE},
"logic_sequence": "{LOGIC_SEQUENCE}",
"filters": [{FILTERS}],
"sorts": [{"{SORT_FIELD}": {"order": "{SORT_ORDER}"}}],
"order_direction": "next",
"search_after": [],
"size": {SIZE},
"show_detail_on_record": false
}type(số, ở cấp cao nhất, luôn truyền tường minh, không dựa vào mặc định):1AND,2OR,3CUSTOM. Đã kiểm chứng: thiếutypetrả HTTP 400,r: 27,msg: Invalid filter type; cùng request thêmtype: 1thành công.typekhácfilters[].fieldType; không sửafieldTypeđể chữa lỗi này.logic_sequence:""khitypelà1/2; khi3là biểu thức như"1 AND (2 OR 3)"(số là thứ tự phần tử trongfilters, bắt đầu từ 1).filters[]:{"field": "<slug>", "op": "<toán tử>", "params": <null | string | number | array>, "fieldType": "<fieldType từ $object-info>"}. Toán tử và kiểuparamstheo từngfieldType: records_filter_conditions.md; field và đường dẫn không lọc được: Trường hợp không hỗ trợ. Lấy tất cả bản ghi:{"field": "id", "op": "not null", "params": null, "fieldType": "short_text"}; lọc trạng thái:{"field": "status", "op": "in", "params": ["new", "nurturing"], "fieldType": "single_choice"}.sorts: field mặc địnhupdated;orderlàdesc(mới nhất trước) hoặcasc.size: mặc định20, tối đa100(lớn hơn được hạ về 100);0chỉ trảdata.total(đếm, không lấy bản ghi). Phân trang: lần đầu"search_after": [], các lần sau truyềndata.search_aftercủa response trước. Cần đếm hoặc thống kê theo nhóm thì dùngsize: 0hoặc F. Đếm và thống kê, không phân trang qua mọi bản ghi rồi tự tính.
Response: data.total (tổng bản ghi phù hợp), data.rows[] (mỗi bản ghi gồm id, name, created, updated, created_by{id,name} và các field theo Object), data.search_after (mảng, dùng cho trang tiếp); ngoài data còn personnelId, workspaceDomain, workspaceId. Giá trị trong rows:
boolean:0/1, không phảitrue/false.url: mảng object[{"alias": "", "url": "https://..."}], không phải mảng string.lookup_normal/reference: full object của bản ghi được lookup (id,namevà các field khác).long_text: chuỗi thuần; field bật từ 2 định dạng trở lên trả chuỗi JSON"{\"text_type\":2,\"value\":\"<p>...</p>\"}"phải parse, xem Fieldlong_text.
B. Tạo — POST /bapi/v1/records
{"object_slug": "{OBJECT_SLUG}", "data": {"{FIELD_SLUG}": {VALUE}}, "client_time_zone": "Asia/Saigon"}data chứa các cặp field_slug: value đúng kiểu theo bảng dưới, gồm mọi field bắt buộc. Thành công: r: 0, data.id là ID bản ghi mới (dùng cho cập nhật/xoá); lỗi: r: 1 kèm msg.
Chế độ ghi write_mode (dùng cho B, C, D)
Tham số tuỳ chọn ở cấp cao nhất của body (cạnh object_slug/object_type), chữ thường; quyết định Process kích hoạt theo bản ghi chạy ngay hay chạy dần:
| Giá trị | Hành vi | Khi dùng |
import (mặc định khi không gửi) | Coi là ghi hàng loạt: Process kích hoạt theo bản ghi được xếp hàng và chạy dần, có thể chậm vài giây tới vài phút khi tải cao, không ảnh hưởng thao tác thường của người dùng. Lượt chạy sinh ra từ đó khi ghi bản ghi khác cũng ghi theo import | Đồng bộ, nhập, sửa hàng loạt |
interactive | Như thao tác trên giao diện: Process kích hoạt gần như ngay | Tích hợp cần phản hồi tức thì, ví dụ biểu mẫu web tạo khách hàng tiềm năng; kiểm thử Process Triggered record |
{"object_slug": "{OBJECT_SLUG}", "write_mode": "interactive", "data": {"{FIELD_SLUG}": {VALUE}}}Giá trị khác trả HTTP 400, r: 100006. Phiên Web App đổi từ /bapi/v1/auth-token ghi bản ghi qua /api/v1 (như bước 5 của E) cũng mặc định import và nhận write_mode; phiên đăng nhập Web thường luôn là thao tác thường. Nhập dữ liệu từ file Excel luôn là import.
Giá trị theo kiểu trường (dùng cho B và C)
| Kiểu trường | Giá trị | Ví dụ |
short_text, phone, email | String | "Nguyễn Văn A", "0901234567", "a@example.com" |
long_text | Theo số định dạng bật trong metaData.text_types, xem Field long_text | Bật 1 định dạng: "<p>Mô tả</p>"; bật từ 2 định dạng: {"text_type":2,"value":"<p>Mô tả</p>"} |
boolean | true/false (response trả 1/0) | true |
single_choice | Slug của option | "new", "qualified" |
multi_choices | Mảng slug option | ["option1", "option2"] |
numeric, currency, rating | Number | 100, 1500000, 3 |
percent | Number 0–1 | 0.75 |
date | String YYYY-MM-DD | "2026-02-12" |
date_time, time_duration | Timestamp (ms) | 1770650967000; 3600000 (1 giờ) |
url | Object (đơn) hoặc mảng object (nhiều) | {"alias":"","url":"https://example.com"}; [{"alias":"","url":"https://a.example.com"},{"alias":"","url":"https://b.example.com"}] |
regex | String khớp pattern metaData.regex của field trong object info | Pattern ^\d{12}$ → "123456789012" |
lookup_normal, reference | Record ID | "PER00000000003" |
file | Metadata upload: object nếu đơn, mảng nếu multiple | references/upload-file.md |
Field long_text
Lấy metaData.text_types của field qua $object-info trước khi ghi. Ba định dạng: 1 plain text, 2 rich text (HTML), 3 markdown; metaData.text_type là định dạng mặc định. Field tạo trước đây có thể không có text_types mà chỉ có text_type hoặc rich_text: "Yes": coi như bật đúng 1 định dạng.
text_types | Ghi (B, C) | Đọc (A) |
| Đúng 1 phần tử | Chuỗi thuần theo định dạng đó: [1] → "Giao hàng trước 17h"; [2] → "<p>Giao hàng <strong>trước 17h</strong></p>"; [3] → "Giao hàng **trước 17h**" | Chuỗi thuần như đã ghi |
| Từ 2 phần tử | Object {"text_type": 3, "value": "Giao hàng **trước 17h**"}; text_type phải thuộc text_types | Chuỗi JSON "{\"text_type\":3,\"value\":\"Giao hàng **trước 17h**\"}", parse để lấy text_type và value |
- API không kiểm tra cấu trúc và vẫn trả
r: 0khi gửi sai: object vào field bật 1 định dạng bị lưu nguyên chuỗi JSON và UI hiển thị{"text_type":2,"value":...}; chuỗi thuần vào field bật từ 2 định dạng bị lưu thiếutext_type. Sau khi ghi phải đọc lại giá trị field, không chỉ dựa vàor: 0. - Bỏ trống field bật từ 2 định dạng: gửi
{"text_type": 1, "value": null}để đồng nhất với UI (API cũng chấp nhậnnull, khi đó field biến mất khỏi response). Khi đọc, coi là rỗng cả bốn trường hợp: thiếu key,null, JSON có"value": null, JSON có"value": "". - Không ghi vào field bóng
_hidden_<slug>(metadataoriginalId) mà hệ thống tạo kèm mỗi fieldlong_text.
Tạo kèm file
Theo references/upload-file.md: upload riêng cho từng field đích bằng phiên Web App để lấy FILE_METADATA, rồi đưa metadata vào data của đúng một request create cùng các field thường và bắt buộc (field đơn: object, field đa: mảng). Không gọi thêm POST /api/v1/records sau khi create trả r: 0. Đọc lại record để xác minh.
Tạo kèm ảnh local trong long-text WYSIWYG
Theo references/wysiwyg-long-text-images.md: lấy ID field hệ thống _attachments và ID field WYSIWYG qua $object-info (không có _attachments thì dừng), upload ảnh bằng phiên Web App theo field ID và Object ID, rồi tạo record bằng đúng một request /bapi/v1/records với metadata ảnh trong data._attachments và HTML ảnh trong field WYSIWYG theo cấu trúc của Field long_text: chuỗi HTML khi field chỉ bật rich text, object {"text_type":2,"value":"<HTML>"} khi field bật từ 2 định dạng.
C. Cập nhật — PUT /bapi/v1/records/{RECORD_ID}
{"object_slug": "{OBJECT_SLUG}", "data": {"{FIELD_SLUG}": {VALUE}}}data chỉ chứa các field cần cập nhật, giá trị theo bảng ở B; write_mode tuỳ chọn theo Chế độ ghi. RECORD_ID lấy từ kết quả A hoặc từ người dùng. Thành công: r: 0, data: {}. r: 1 với msg: "Record not existed": RECORD_ID sai hoặc bản ghi đã bị xoá; báo người dùng kiểm tra lại hoặc dùng A để tìm.
D. Xoá — POST /bapi/v1/records/delete
Hành động không thể hoàn tác. BẮT BUỘC liệt kê ID (và tên nếu có) các bản ghi sẽ xoá, hỏi và chỉ gọi API khi người dùng xác nhận đồng ý; người dùng từ chối thì huỷ và thông báo.
{"object_type": "{OBJECT_TYPE_ID}", "ids": ["{RECORD_ID_1}", "{RECORD_ID_2}"]}object_type là ID của Object (ví dụ OT00000000011, lấy qua $object-info); ids nhận nhiều bản ghi cùng lúc; write_mode tuỳ chọn theo Chế độ ghi. Thành công: r: 0, data.deleted[] (đã xoá) và data.not_deleted[] (không xoá được). r: 1 với msg: "Record not existed": có ID sai hoặc đã bị xoá trước đó.
Record của Object mà backend App chuẩn duy trì số liệu (ví dụ chứng từ đang giữ chỗ ngân sách): xoá record có thể không hoàn lại số liệu backend đã cập nhật (quan sát: số giữ chỗ còn treo sau khi xoá chứng từ đang chờ duyệt). Ưu tiên huỷ, từ chối hoặc đóng bằng trạng thái/action của App; chỉ xoá khi người dùng xác nhận đã biết tác động. Hành vi từng App: $cogover-overview.
E. Gắn file vào bản ghi hiện có
Thực hiện bằng API, không dùng trình duyệt. Đọc references/upload-file.md trước khi gọi.
- Xác định
WORKSPACE_DOMAIN,OBJECT_SLUGvàRECORD_IDtừ URL bản ghi hoặc ngữ cảnh; xác minh file cục bộ tồn tại và không rỗng. - Dùng
$object-infolấyOBJECT_TYPE_IDvà xác minh từng field đích cófieldType=file; giữ nguyênFILE_FIELD_SLUGvà cờmultipletừ metadata. - Tạo phiên Web App qua
$cogover-api-authcho các endpoint/api/v1. - Upload riêng cho từng field đích bằng
POST /api/v1/file/upload/v2/client_upload; cùng một file gắn vào nhiều field vẫn cần mỗi field một request vớifield_slugtương ứng và mộtFILE_METADATAriêng. Chỉ tiếp tục khi upload trả HTTP2xx,r: 0và có objectdata. - Sau khi mọi upload thành công, gắn metadata bằng
POST /api/v1/records; có thể gắn nhiều field trong cùng request, không tái sử dụng metadata cho field khác. Field đơn (multiple=false) gửi object, field đa (multiple=true) gửi mảng; nếu người dùng muốn thêm file mà không thay file cũ, đọc giá trị hiện tại và nối metadata mới trước khi gửi. - Hoàn tất chỉ khi request gắn file trả HTTP
2xxvàr: 0(kiểm tra cảbody.r). Báo tên file, Object/field slug, cờ đơn/đa, ID bản ghi và kết quả từng bước.
F. Đếm và thống kê — POST /bapi/v1/records/aggregate
Đếm và tính số liệu theo nhóm trên toàn bộ bản ghi khớp bộ lọc trong một request. Cùng API Key Bearer và giới hạn tần suất như /records/list.
{
"object_slug": "{OBJECT_SLUG}",
"type": 1,
"logic_sequence": "",
"filters": [{"field": "status", "op": "in", "params": ["new"], "fieldType": "single_choice"}],
"group_by": ["{GROUP_FIELD_SLUG}"],
"stats": [{"type": "count"}, {"type": "sum", "field": "{NUMBER_FIELD_SLUG}"}],
"group_limit": 1000
}| Trường | Quy tắc |
object_slug | Bắt buộc |
type, logic_sequence, filters | Như A; filters rỗng hoặc thiếu là mọi bản ghi. Không lọc theo field của bản ghi liên quan (owner.name): lọc theo ID lookup |
group_by | 0–3 slug field; rỗng là đúng một nhóm {"key":{}} gồm mọi bản ghi khớp. Không nhóm được long_text, phone, file, formula, rollup; reference chỉ nhóm một mình |
stats | Tối đa 10 phần tử {type, field}: count (luôn có), sum/avg trên field số, min/max trên field số hoặc ngày, distinct (số giá trị khác nhau của field, gần đúng khi rất nhiều giá trị) |
group_limit | 1–10000, mặc định 1000; nhóm xếp theo count giảm dần |
Response:
{"r":0,"msg":"OK","data":{"total":2095,"groups":[{"key":{"owner":{"id":"PER00000000003","name":"Nguyễn Văn A"}},"count":872,"sum_amount":1500000}],"truncated":false}}data.total: số bản ghi khớp bộ lọc trong phạm vi quyền của người gọi. Mỗi phần tửgroups[]cókey(slug field → giá trị),countvà<type>_<field>cho mỗi chỉ số thêm (ví dụsum_amount).- Giá trị trong
key: lookup/reference{id, name}; lựa chọn là slug option; booleantrue/false;datechuỗiYYYY-MM-DD;date_timetimestamp (ms); số là number; text là string, có thể trả về dạng chữ thường. - Nhóm theo một field: bản ghi không có giá trị thành một nhóm có giá trị
keylànull. Nhóm theo nhiều field không có nhóm này; với field một giá trị, số bản ghi trống làtotaltrừ tổngcount. truncated: truekhi số nhóm vượtgroup_limit: tănggroup_limithoặc thu hẹp bộ lọc trước khi kết luận về các nhóm nhỏ.- Áp dụng quyền Object/record của người gọi; field bị ẩn với người gọi không dùng được trong
group_by,stats,filters. - Lỗi trả HTTP 400 với
r:80body sai,81field không có hoặc không nhóm/tính được,82field bị ẩn với người gọi,83API Key không gắn nhân sự,40không có quyền xem Object,1Object không tồn tại;14lỗi tìm kiếm phía server (thử lại sau).
Chỉ cần tổng số thì dùng /records/list với size: 0. Báo cáo cần lưu lại, kết hợp nhiều Object hoặc dùng lại trên dashboard: dùng $report-builder.
Dữ liệu kiểm thử
Nguồn chung cho dữ liệu kiểm thử của bộ skill; skill khác chỉ ghi phần riêng.
- Tạo record test riêng, gắn marker dễ tìm trong field tìm kiếm được (ví dụ tiền tố
[TEST]trongname); không chạy kịch bản thử trên record demo hoặc dữ liệu thật. - Luồng làm thay đổi số liệu do backend duy trì (ngân sách, quỹ, công nợ, tồn kho): dùng số nhỏ và tài nguyên riêng cho test, chọn record tổng hợp ít dữ liệu thật, snapshot các record tổng hợp bị ảnh hưởng trước và sau.
- Trước khi chạy, liệt kê và hỏi người dùng về thao tác không hoàn tác được (chứng từ đã duyệt hoặc kích hoạt không huỷ được, phiếu thu chi đã hoàn thành, số liệu backend đã ghi, email hay thông báo thật, record bị Process khác cập nhật dây chuyền).
- Kết thúc chứng từ test bằng trạng thái nghiệp vụ (đóng, huỷ, từ chối), không xoá chứng từ đã giữ chỗ hoặc đã phát sinh bút toán (xem D. Xoá).
- Không sửa tay số liệu do backend hoặc module duy trì để "dọn": record tổng sẽ lệch với tổng record chi tiết còn lại (quan sát: xoá chứng từ đang chờ duyệt để lại số giữ chỗ; sửa tay làm lệch tổng). Phần dư không hoàn tác được báo người dùng kèm giá trị và record liên quan; chỉ sửa tay khi người dùng duyệt từng giá trị.
- Thử thao tác trên giao diện: layout Xem có thể tự lưu khi rời ô (inline edit); chỉ thao tác trên record test, lưu nhầm thì khôi phục qua API và báo lại.
- Persona, API key tạm và dọn dẹp sau kiểm thử quyền: theo $user-permission.
Trả kết quả
- Người dùng gọi trực tiếp: bảng hoặc danh sách dễ đọc. Danh sách: các trường quan trọng (
id,name,status,created...); nhiều bản ghi thì tóm tắt và hỏi có xem thêm không. Thống kê: bảng nhóm kèmtotal, nêu rõ khitruncated: true. Tạo: kèm ID bản ghi mới. Xoá: nhấn mạnh bản ghi đã bị xoá vĩnh viễn. Upload: như bước 6 của E. - Skill khác gọi: trả dữ liệu có cấu trúc để skill gọi dùng trực tiếp.
Xử lý lỗi
| Lỗi | Cách xử lý |
r: 27 — Invalid filter type | Request /records/list thiếu hoặc sai type: thêm type số 1/2/3 ở cấp cao nhất và đối chiếu logic_sequence. Không thay filters[].fieldType để chữa. |
HTTP 400, r: 100006 khi tạo/cập nhật/xoá | write_mode sai giá trị: chỉ gửi import hoặc interactive (chữ thường), hoặc bỏ tham số để dùng mặc định import. |
| Process kích hoạt theo bản ghi chạy chậm sau khi ghi qua API | Hành vi của write_mode: import (mặc định); gửi interactive khi cần phản hồi tức thì, xem Chế độ ghi. |
r: 1 — Record not existed | RECORD_ID sai hoặc bản ghi đã bị xoá; kiểm tra lại hoặc dùng A để tìm. |
HTTP 400, r 81/82 khi gọi /records/aggregate | 81: field không có hoặc không nhóm/tính được theo kiểu; 82: field bị ẩn với người gọi. Đối chiếu field và request theo F, bỏ field đó hoặc kiểm tra quyền theo $user-permission; không thử lại bằng key khác. |
r: 47 — Field [...] is not editable | Field không cho sửa qua API: manualModifyAllow: false, formula, rollup, field hệ thống hoặc field do backend App quản lý (ví dụ status của một số Object App chuẩn). Đọc metadata field qua $object-info trước khi PUT; đổi trạng thái bằng Object Button, Process hoặc action của App, không thử lại PUT. |
r: 37 — You don't have permission to update this record | Security rule hoặc khoá sửa theo trạng thái chặn field/record, áp dụng cả Super Admin. Báo đúng field bị chặn; không thử lại bằng key khác, không tự mở rule. Sửa dữ liệu đã khoá: theo Khoá sửa theo trạng thái, hỏi người dùng phạm vi trước. |
r: 48 — target value không được phép | Transition rule không có flow từ giá trị hiện tại sang giá trị đích. Đọc rule qua $object-transition-rule; không nhảy cóc trạng thái. |
r: 41 khi tạo | Quan sát, cần kiểm chứng: đã gặp khi Role của người gọi chưa có quyền create trên Object; kiểm tra Role theo $user-permission. |
r: 14 — Fetching data failed; r: 25 — Invalid filter | Bộ lọc rơi vào Trường hợp không hỗ trợ. |
r: 626 khi gắn file (not found file id) | Sai kiểu đơn/đa: không bọc object metadata trong mảng với field đơn. |
| Timeout hoặc mất kết nối khi upload, gắn file, create | Không tự retry vì thao tác ghi có thể đã xảy ra; báo kết quả chưa xác định, chỉ thử lại khi người dùng yêu cầu rõ. Timeout khi đọc: thử lại khi phù hợp yêu cầu. |
| Create lỗi sau khi upload | Báo các file ID đã upload có thể bị mồ côi; không tự retry create. |
| Không tạo được phiên Web App | Dừng và báo người dùng; không gọi /api/v1 bằng API Key. |
Không tìm thấy field _attachments | Đọc lại Object fields; không upload ảnh WYSIWYG khi chưa xác định được field ID này. |
UI hiển thị {"text_type":...,"value":...} hoặc mất định dạng ở field long_text | Đã gửi sai cấu trúc so với metaData.text_types; cập nhật lại field bằng đúng cấu trúc theo Field long_text rồi đọc lại. |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

