---
id: DOM-PFM-MTD-005
title: Custom Record
realises: CON-PFM-MTD-005
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: confirmed
origin: Custom objects architecture D-01, D-02, D-03, D-09, D-10, D-19 (approved 2026-10-18) and PLAT-M5 D3, D4,
  D5, B1, B5 (services-platform:docs/milestones/PLAT-M5-custom-records.md#Decisions; Product Accepted 2026-10-20);
  record history plan approved 2026-10-11 (services-platform:docs/record-history.md); business events contract (services-platform:docs/business-events.md,
  PLAT-M7 proposed, so the event facet stays proposed)
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-PFM-MTD-custom-objects
readable_by:
- SVC-PFM-MTD-associations
- SVC-PFM-MTD-metadata
lifecycle: STATE-PFM-MTD-005
custom_fields: declared
identity: Creation fixes record identity before attachments are prepared. The object’s definitions determine validation
  and naming; archival retains content, while deletion removes record data and preserves history.
attributes:
- name: object
  kind: reference
  required: true
  computed: false
  notes: The parent object identity is fixed, and ordinary record writes require an active parent.
- name: number
  kind: number
  required: true
  computed: true
  notes: The object's numbering sequence allocates a number unique for that object in the workspace.
- name: display name
  kind: computed
  required: true
  computed: true
  notes: Each write composes the display value and secondary values, or falls back to the prefixed number. The resulting
    name is limited to five hundred characters.
- name: property values
  kind: collection
  required: false
  computed: false
  notes: Live definitions and rules govern typed property values. Decimal, money and percentage values also have
    a precision-scaled comparison shadow when it fits the supported range.
- name: unique value reservations
  kind: collection
  required: false
  computed: true
  notes: Unique properties reserve normalized values for their holding record.
- name: files
  kind: collection
  required: false
  computed: true
  notes: Attachment values reference permanent copies prepared by the asset pipeline, with lifecycle entries for
    each file.
- name: publication state and published at
  kind: enum
  required: false
  computed: false
  notes: Publishable objects support draft, review, published and unpublished states. A publication timestamp exists
    exactly while the record is published.
- name: archived at
  kind: date
  required: false
  computed: false
  notes: Archival retains content but excludes the record from ordinary lists. Restoration or permitted deletion
    remains available.
- name: external identifier
  kind: text
  required: false
  computed: false
  notes: An optional caller identity is unique per object; changing only that identifier emits no event.
- name: version, lock and modification facts
  kind: computed
  required: true
  computed: true
  notes: Record mutations require the read version and apply the relevant lock checks.
- name: links
  kind: collection
  required: false
  computed: true
  notes: Record reads assemble current links grouped by type; Associations owns the underlying connections.
- name: history · revisions
  kind: collection
  required: true
  computed: true
  notes: Database capture retains attributed before-and-after revisions for business changes, including property
    and link changes, until authorized workspace purging.
- name: business event · ledger and delivery work
  kind: collection
  required: false
  computed: true
  notes: Supported changes append created, updated, archived, restored, published, unpublished or deleted facts
    and waiting delivery rows. The ledger retention is ninety days except where an outbox reference still protects
    an event.
relationships:
- to: DOM-PFM-MTD-004
  cardinality: many-to-one
  ownership: The record stores its parent identity and follows that object's lifecycle and naming configuration.
  cross_service: false
- to: DOM-PFM-MTD-002
  cardinality: many-to-many
  ownership: Metadata owns definitions; the record owns each keyed property value.
  cross_service: false
- to: DOM-PFM-MTD-006
  cardinality: one-to-many
  ownership: Associations owns links naming the record; deletion applies link policy, and reference values can target
    native or custom records.
  cross_service: true
invariants:
- id: INV-DOM-PFM-MTD-005-01
  statement: Ordinary mutations require an active parent object; records under draft or archived definitions remain
    readable by identity and reject direct writes.
  enforced_at:
  - service
  provenance: test
  source: services-platform:modules/custom-objects/tests/e2e/custom-object-records.e2e.spec.js#refuses every write
    of it with 409 and changes nothing
- id: INV-DOM-PFM-MTD-005-02
  statement: The write validates live properties and rejects unknown, archived or invalid inputs at the property
    key without echoing values.
  enforced_at:
  - service
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#names
    the object’s label in that refus
- id: INV-DOM-PFM-MTD-005-03
  statement: Unique properties permit one holding record per normalized value, trimming and case-folding text.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
    a hull number another boat hol
- id: INV-DOM-PFM-MTD-005-04
  statement: References resolve in the workspace to their declared target type, and custom targets must be unarchived.
  enforced_at:
  - service
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
    a manufacturer that is a boat
- id: INV-DOM-PFM-MTD-005-05
  statement: Published records carry a publication timestamp, and nonpublishable objects reject publication actions.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
    publication on an object that
- id: INV-DOM-PFM-MTD-005-06
  statement: Changed attachment values require asset preparation; direct unprepared references cannot be persisted.
  enforced_at:
  - service
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#names
    a create’s missing upload at pro
- id: INV-DOM-PFM-MTD-005-07
  statement: Version checks prevent stale record mutations, and applicable locks block writes.
  enforced_at:
  - service
  provenance: test
  source: 'react-console:acceptance/custom-objects/playwright/journeys/PLAT-M5-S06.spec.ts#PLAT-M5-S06: two registrars
    edit one boat; the second is told and nothing is los'
- id: INV-DOM-PFM-MTD-005-08
  statement: In-force restricting links refuse deletion; custom-record cascades are bounded to depth ten and roll
    back together on refusal.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
    to delete a record an open res
- id: INV-DOM-PFM-MTD-005-09
  statement: Business changes require attributed commit-time history, while unchanged business values create no
    revision.
  enforced_at:
  - database
  provenance: documented
  source: services-platform:docs/record-history.md#Rules every writer meets
- id: INV-DOM-PFM-MTD-005-10
  statement: Events are appended with supported committed changes; refused writes, rollback and changes outside
    event content produce none.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.events.integration.spec.js#publishes
    nothing when the tran
- id: INV-DOM-PFM-MTD-005-11
  statement: Mutations and single-record views record audits in their transaction without business values.
  enforced_at:
  - service
  provenance: test
  source: services-platform:modules/custom-objects/tests/e2e/custom-object-records.e2e.spec.js#audits the read of
    a record as a view
- id: INV-DOM-PFM-MTD-005-12
  statement: Caller external identities are unique within their object.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
    a create under an external id
physical:
- platform.custom_object_records
- platform.custom_object_record_values
- platform.custom_object_unique_values
- platform.managed_assets
- platform.record_revisions
- platform.custom_object_record_change_events
- platform.business_events
- platform.business_event_queue
evidence:
- 'services-platform at ad3f6a65: modules/custom-objects/services/persistence/custom-object-records.ts, record-revisions.ts,
  business-events.ts; services/assets/custom-object-record-assets.ts; services/dispatch/business-events.ts; record-rules.ts;
  record-events.ts; exposure.ts; history/custom-object-record-history.config.ts; db/*.table.ts; docs/custom-objects.md
  §12 to §24; docs/business-events.md; docs/record-history.md; docs/assets.md §5 and §7'
- 'react-console at baf6dae3: components/console/custom-objects/record-editor.tsx, custom-record-screen.tsx, record-action-panels.tsx;
  lib/forms/custom-objects/owner.ts'
---

# Custom Record

## What It Models

A custom record is one entry in an organization’s register. It combines typed property values with a derived number and name, optional publication, attachments, links and retained revisions.

## Identity and Attributes

Creation fixes record identity before attachments are prepared. The object’s definitions determine validation and naming; archival retains content, while deletion removes record data and preserves history.

## Relationships

The parent controls ordinary write availability, properties govern values, and Associations owns the links that influence deletion.

## Invariants

Record saves apply current rules and concurrency checks. Supported mutations commit audit, history and events together, and deletion follows relationship safeguards within one transaction.

## How It Is Stored and Shared

Custom Objects owns the shared record and value store. Queries reads it through granted interfaces; endpoint functions let CRM apply transactional deletion and merge effects. The event queue handles delivery after commit.

## Open Design Questions

Platform’s asset cleanup is absent, leaving abandoned or detached copies. Per-owner limits and HTML processing are separate unresolved planning issues.
