Bỏ qua để đến nội dung

Mở rộng & tuỳ biến

  1. Thêm field vào shared/types/contact.ts (interface Contact — cho TypeScript).

  2. Thêm field vào app/data/contacts-schema.ts (mảng fields, đúng collection: "c_contacts") — áp dụng cho cài đặt mới chạy wizard từ đầu.

  3. Nếu backend đã tồn tại (không chạy lại wizard), tạo field trực tiếp qua ODP API hoặc Data Studio.

  4. Thêm tên field vào layout tương ứng trong app/config/form-layouts.ts (PERSON_FORM_LAYOUT/ORGANIZATION_FORM_LAYOUT/PROFILE_FORM_TAB) để field xuất hiện trên form — field registry tự đọc metadata (type, interface, required…) từ backend, bạn chỉ cần khai báo field này ở tab/section nào.

  5. Nếu cần đọc field ở trang chi tiết (không phải form), thêm vào app/config/info-layouts.ts.

Thêm sub-collection mới (vd c_contact_documents)

Phần tiêu đề “Thêm sub-collection mới (vd c_contact_documents)”
  1. Thêm collection + field + relation vào contacts-schema.ts (tôn trọng thứ tự phụ thuộc FK — bảng con luôn sau c_contacts).

  2. Thêm controller mới trong backend/extensions/contacts/src/endpoints/controllers/ (tham khảo notes.controller.ts hoặc social-links.controller.ts nếu chỉ cần CRUD O2M đơn giản), đăng ký route trong routes.ts với đúng action guard (read/update…).

  3. Nếu form cần field metadata của collection mới, thêm entry vào COLLECTION_MAP trong backend/extensions/contacts/src/endpoints/controllers/meta.controller.ts (map tên rút gọn → tên bảng thật).

  4. Nếu xoá contact cần xoá luôn bản ghi con mới, thêm tên collection vào CHILD_COLLECTIONS trong cascade-delete.ts.

  5. Thêm route BFF trong server/api/contacts/[id]/<ten>/ (theo mẫu social-links/), rồi composable use-contact-<ten>.ts gọi các route đó.

  6. Thêm component + wire vào trang chi tiết (contact-info-tab.vue hoặc một tab riêng).

Cắm tab vào trang chi tiết contact (từ module của bạn)

Phần tiêu đề “Cắm tab vào trang chi tiết contact (từ module của bạn)”

Không cần sửa gì trong Contacts — chỉ cần một plugin trong module của bạn:

app/plugins/<ten-module>-contacts-extension.ts
export default defineNuxtPlugin(() => {
const ext = useExtensionStore()
ext.register("contacts.detail.tabs", {
id: "your-module-id", // duy nhất trong điểm mở rộng này
label: "Tên tab hiển thị",
icon: "i-ph-...",
component: defineAsyncComponent(() => import("../components/contacts/your-tab.vue")),
sort: 40, // thứ tự so với tab lõi (info=0, notes=10)
visible: ctx => ctx.contact?.type === "person", // tuỳ điều kiện
})
})

Component nhận prop contact (object contact đầy đủ) — xem chi tiết cơ chế ở Extension store.

Không cần thay đổi code phía Contacts — intake là source-agnostic theo thiết kế. Chỉ cần module của bạn gọi:

await $fetch("/api/intakes", {
method: "POST",
body: {
name, email, phone,
source_module: "ten-module-cua-ban",
source_ref: "id-tham-chieu-o-module-ban",
source_label: "Mô tả người-đọc-được",
raw_payload: { /* dữ liệu gốc tuỳ ý */ },
suggested_type: "lead", // tuỳ chọn
},
})

Ràng buộc duy nhất: phải có email hoặc phone. Chi tiết ở Intake pipeline.

Nếu module của bạn cần một loại quan hệ riêng (vd hr:employee) hiện trong bộ lọc/filter của Contacts mà không cần ghi vào bảng shared_types dùng chung:

app/plugins/<ten-module>-contact-types.ts
export default defineNuxtPlugin(() => {
const { register } = useContactTypeRegistry()
register({ key: "hr:employee", label: "Employee", icon: "i-ph-user-light", color: "info", owner_module: "hr" })
})