---
id: CAP-CRM-ENT-018
title: Organize the workspace’s record classifications
product_area: crm
module: entities
revision: 1
status: approved
product_intent: proposed
implementation_evidence: observed
source_sha:
  services-crm: 7ea48a414c42eade10d60753b8bcc323b1dd726f
  react-console: da63075876b2c5f4a6af07d457bb24ea8bf4c0c7
intent_sources:
  - 'OQ-CRM-ENT-002 decided 2026-10-22 by Andrew: B (classification types and the role catalogue stay in Entities)'
  - 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#M1-D2'
  - 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#M1-D8'
  - 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#D-08'
  - 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.plan.md#A17'
purpose: >-
  Administrators maintain the categories used to classify records and their
  contact details.
outcomes:
  - Every type a record names is the tenant’s own.
  - A type in use cannot be deleted.
  - The tenant decides the order pickers and defaults follow.
actors:
  - ACT-CRM-001
  - ACT-CRM-003
  - ACT-CRM-004
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: crm.contact-types.read
    where_checked: api
    scope: tenant
  - key: crm.contact-types.create
    where_checked: api
    scope: tenant
  - key: crm.contact-types.update
    where_checked: api
    scope: tenant
  - key: crm.contact-types.delete
    where_checked: api
    scope: tenant
  - key: crm.organization-types.read
    where_checked: api
    scope: tenant
  - key: crm.organization-types.create
    where_checked: api
    scope: tenant
  - key: crm.organization-types.update
    where_checked: api
    scope: tenant
  - key: crm.organization-types.delete
    where_checked: api
    scope: tenant
  - key: crm.address-types.read
    where_checked: api
    scope: tenant
  - key: crm.address-types.create
    where_checked: api
    scope: tenant
  - key: crm.address-types.update
    where_checked: api
    scope: tenant
  - key: crm.address-types.delete
    where_checked: api
    scope: tenant
  - key: crm.phone-number-types.read
    where_checked: api
    scope: tenant
  - key: crm.phone-number-types.create
    where_checked: api
    scope: tenant
  - key: crm.phone-number-types.update
    where_checked: api
    scope: tenant
  - key: crm.phone-number-types.delete
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-CRM-ENT-018-01
    proved_by: [ATS-CRM-ENT-018-01, TST-CRM-ENT-786]
    statement: >-
      Contact, organization, address and phone types require trimmed nonblank
      names, and invalid creation writes no type.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 naming the field for a create whose name is nothing but spaces
    origin: none
  - id: BR-CAP-CRM-ENT-018-02
    proved_by: [ATS-CRM-ENT-018-02, TST-CRM-ENT-786]
    statement: >-
      Classification ids follow lowercase configuration-id grammar, can derive
      from names, cannot use API-reserved ids or duplicate a tenant id, and must
      match the path on replacement.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 for an id that is not a configuration id, saying what an id may hold
    origin: none
  - id: BR-CAP-CRM-ENT-018-03
    proved_by: [ATS-CRM-ENT-002-18, ATS-CRM-ENT-017-17, ATS-CRM-ENT-018-03, ATS-CRM-ENT-018-10, ATS-CRM-ENT-018-14, TST-CRM-ENT-786]
    statement: >-
      Classification types referenced by records cannot be deleted, including
      contact and organization classifications and types used by address or
      phone elements, with dependent records identified.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/address-types.e2e.spec.js#says
      which records keep the type when it refuses the delete
    origin: none
  - id: BR-CAP-CRM-ENT-018-04
    proved_by: [ATS-CRM-ENT-018-04, TST-CRM-ENT-786, TST-CRM-ENT-787]
    statement: >-
      Type reorder assigns consecutive positions to the complete tenant list,
      rejects omissions, duplicates and unknown ids without changing order,
      permits locked-type movement, appends new address and phone types and
      alphabetizes never-ordered contact and organization types.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 for a reorder that leaves a type of the tenant out
    origin: 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#D-08'
  - id: BR-CAP-CRM-ENT-018-05
    proved_by: [ATS-CRM-ENT-005-16, ATS-CRM-ENT-018-05, ATS-CRM-ENT-018-11, TST-CRM-ENT-786]
    statement: >-
      Address and phone types apply to contacts, organizations or both, default
      to contacts, support applicability filtering and may change applicability
      while still referenced.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/phone-number-types.e2e.spec.js#answers
      only the types usable on organizations when the query asks for them
    origin: 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#M1-D8'
  - id: BR-CAP-CRM-ENT-018-06
    proved_by: [ATS-CRM-ENT-018-06, ATS-CRM-ENT-018-16, TST-CRM-ENT-786]
    statement: >-
      Type reads require reader permissions, contact and organization type
      creation and updates use user permissions, their deletes use administrator
      permissions, and all address and phone type writes including reorders
      require administrator permissions.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/address-types.e2e.spec.js#answers
      403 to a read-only caller’s reorder
    origin: none
  - id: BR-CAP-CRM-ENT-018-07
    proved_by: [ATS-CRM-ENT-012-23, ATS-CRM-ENT-015-14, ATS-CRM-ENT-018-07, ATS-CRM-ENT-018-12, ATS-CRM-ENT-018-13, ATS-CRM-ENT-018-15, ATS-CRM-ENT-019-10, TST-CRM-ENT-786]
    statement: >-
      Type replacement requires the read version, clears omitted replaceable
      values and preserves layout assignments; patches change named values, full
      locks block updates and deletes, and delete locks block deletes.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#then,
      when the version is off, refuses the change (409)
    origin: 'Behaviour at the pinned commit; OQ-CRM-ENT-001 decided 2026-10-22 by Andrew: A (classification records follow the complete-payload rule too, see BR-CAP-CRM-ENT-004-13)'
  - id: BR-CAP-CRM-ENT-018-08
    proved_by: [ATS-CRM-ENT-001-22, ATS-CRM-ENT-018-08, ATS-CRM-ENT-018-09, TST-CRM-ENT-774]
    statement: >-
      Contacts retain inactive types, while creation offers only active types
      and preselects a sole available type.
    kind: policy
    enforced_at:
      - console
      - service
    must_prove: false
    provenance: test
    source: >-
      react-console:acceptance/crm/playwright/journeys/contacts/CRM-ACC-0033.spec.ts#CRM-ACC-0033
    origin: 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#M1-D2'
scenarios:
  - id: SC-CAP-CRM-ENT-018-01
    given: 'A tenant’s phone types in the order mobile, work, home.'
    when: An administrator moves home first.
    then: New contacts without a marked number get the home number as preferred.
    provenance: test
    source: >-
      react-console:acceptance/crm/playwright/journeys/contacts/CRM-ACC-0062.spec.ts#CRM-ACC-0062
  - id: SC-CAP-CRM-ENT-018-02
    given: An organization type used by an organization.
    when: An administrator deletes it.
    then: The delete is rejected.
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/organization-types.e2e.spec.js#refuses
      an organization of a type the tenant does not have (409), and the delete
      of a type an organization has (409)
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-CRM-ENT-001
  - CAP-CRM-ENT-002
  - CAP-CRM-ENT-005
  - CAP-CRM-ENT-012
  - CAP-CRM-ENT-015
  - CAP-CRM-ENT-017
  - CAP-CRM-ENT-019
journeys:
  - JNY-CRM-ENT-001
  - JNY-CRM-ENT-004
open_questions:
  - OQ-CRM-ENT-002
feature: FEAT-CRM-ENT-06
concepts:
  - CON-CRM-ENT-001
  - CON-CRM-ENT-002
evidence:
  - >-
    `services-crm` at `7ea48a414c42eade10d60753b8bcc323b1dd726f`: examined
    `aws/api/contact-types.routes.ts`, `organization-types.routes.ts`, `address-types.routes.ts`,
    `phone-number-types.routes.ts`, `collection-types.routes.ts`, their schemas and mappers,
    `services/persistence/contact-types.ts`, `organization-types.ts`, `collection-types.ts`,
    `address-types.ts`, `phone-number-types.ts`, `configuration-type-usages.ts`,
    `db/contact-types.table.ts`, `organization-types.table.ts`, `address-types.table.ts`,
    `phone-number-types.table.ts`, `docs/entities-api.md` ("Organization types", "Contact types",
    "Address types and phone number types", "The tenant's own order"); tests
    `e2e/contact-types.e2e.spec.js`, `e2e/organization-types.e2e.spec.js`,
    `e2e/address-types.e2e.spec.js`, `e2e/phone-number-types.e2e.spec.js`,
    `integration/services/persistence/contact-types.integration.spec.js`.
  - >-
    `react-console` at `da63075876b2c5f4a6af07d457bb24ea8bf4c0c7`: examined journeys CRM-ACC-0033,
    0062, 0065, 0071.


    The permission catalogue also publishes configuration bulk keys. FND-CRM-ENT-013 records that
    these keys have no corresponding route in this module.
approved_by: Andrew
approved_at: 2026-10-22
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-DAT-001, TC-DAT-003, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003]
narrative:
  status: verified
  review: NARRATIVE-REVIEW-2026-10-23
narrative_sources:
  - section: Why It Works This Way
    provenance: inferred
    source: >-
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 naming the field for a create whose name is nothing but spaces;
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 for an id that is not a configuration id, saying what an id may hold;
      services-crm:modules/entities/tests/e2e/address-types.e2e.spec.js#says
      which records keep the type when it refuses the delete;
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#answers
      400 for a reorder that leaves a type of the tenant out;
      services-crm:modules/entities/tests/e2e/phone-number-types.e2e.spec.js#answers
      only the types usable on organizations when the query asks for them;
      services-crm:modules/entities/tests/e2e/address-types.e2e.spec.js#answers
      403 to a read-only caller’s reorder;
      services-crm:modules/entities/tests/e2e/contact-types.e2e.spec.js#then,
      when the version is off, refuses the change (409);
      react-console:acceptance/crm/playwright/journeys/contacts/CRM-ACC-0033.spec.ts#CRM-ACC-0033
    note: >-
      Operational rationale inferred from the cited behavior; no personal motive
      or historical decision is asserted.
repositories:
  - repo: services-crm
    role: owner
    paths:
      - modules/configuration-types/
      - modules/entities/
      - modules/entities/tests/e2e/address-types.e2e.spec.js
      - modules/entities/tests/e2e/contact-types.e2e.spec.js
      - modules/entities/tests/e2e/organization-types.e2e.spec.js
      - modules/entities/tests/e2e/phone-number-types.e2e.spec.js
  - repo: react-console
    role: console
    paths:
      - components/configuration/
      - acceptance/crm/playwright/journeys/contacts/CRM-ACC-0033.spec.ts
      - acceptance/crm/playwright/journeys/contacts/CRM-ACC-0062.spec.ts
exercised_by: [FAS-CRM-ENT-05-02, FAS-CRM-ENT-06-01, FAS-CRM-ENT-06-02, FAS-CRM-ENT-06-03, FAS-CRM-ENT-06-04, FAS-CRM-ENT-06-05]
suites: [TST-CRM-ENT-774, TST-CRM-ENT-786, TST-CRM-ENT-787]
---

# Organize the workspace’s record classifications

## Purpose

The workspace needs consistent categories for people, organizations, addresses, and phone numbers. This capability maintains those classifications and their ordering and applicability, so staff select meaningful choices while existing records retain their interpretation. It also distinguishes safe retirement of a used category from deletion of an unreferenced definition.

## How It Works

Authorized users create classifications with nonblank names and stable configuration identities. The service checks grammar, reserved identities, workspace uniqueness, and the identity used by a replacement path. Different catalogue families have different write authority, with address and phone changes requiring administrator permissions.

A reorder supplies every workspace entry once and changes the complete order atomically. Locks protect record content and removal rather than stopping list movement. Address and phone applicability selects people, organizations, or both. A contact keeps a held entry after its type becomes organization-only, but contact-point validation prevents newly choosing that type.

References block deletion of used classifications. Contact creation offers active types and can preselect a sole choice, while existing contacts retain inactive types. Version-tested replacement and patch semantics govern catalogue edits, and presentation assignments have their explicit preservation exception rather than being cleared with unrelated omitted properties.

## Example

An association orders its contact types as Member, Prospect, and Former Member. A coordinator sees active choices during creation. Later an administrator deactivates Prospect; people already classified that way retain it. Trying to delete it while those contacts reference it is refused. Reordering the full catalogue changes presentation consistently without treating a locked type as an obstacle to moving other entries.

The administrator makes Prospect inactive while Ruth's saved record still has that classification. Ruth's record remains interpretable, and a later read still identifies Prospect. A new-contact chooser offers active choices instead. If only one is available, the creation flow can preselect it; with no active type it can offer untyped creation. Those chooser conveniences do not make contact type compulsory in the service. A malformed complete-list reorder refuses the operation before moving any entries, so the administrator rereads the catalogue, includes every current choice once, and resubmits the intended order. Deletion remains a separate reference-aware administrator action.

## Why It Works This Way

Our reading is that stable identities and reference-aware deletion preserve the meaning of saved records even when terminology changes. Active selection and retained inactive classifications separate future entry policy from past classification. Complete-list reorder prevents partial requests from leaving competing positions or silently losing an entry's place.

Applicability expresses whether a contact-point purpose makes sense on a person or an organization. Retaining an existing entry after a policy change avoids blocking unrelated corrections, while preventing new choices respects the changed catalogue. Separate administrator authority for address and phone types reflects their workspace-wide effects, but that rationale is an interpretation rather than a personal motive. Layout preservation keeps classification maintenance from clearing presentation configured elsewhere.

## Relationships

Contact Type and Organization Type classify the parent records. Address and phone types are facets of Contact Details and Communication Preferences and influence value selection there. Resolve the forms and layouts used for CRM records consumes type assignments. Platform security owns permission evaluation, while the configuration function hosts some catalogue routes under Entities' product ownership.
