Skip to content

CAP-CRM-ENT-002Establish an organization and its hierarchy

Markdown

CAP-CRM-ENT-002

Establish an organization and its hierarchy

Markdown
  • DocumentApproved
  • Product intentConfirmed
  • ImplementationPartially observed

KindCapabilityProduct areaCRMModuleEntitiesRevision1Approved byAndrewApproved at2026-10-22

Read atservices-crm 7ea48a41react-console da630758

The Formal Contract

The narrative above explains; the sections below are authoritative — the rules, scenarios and tests this document binds.

Outcomes
An organization exists with its number, id, type and parent, and its ancestry is returned on every read.A loop in the hierarchy can never be saved.A rejected create writes nothing and reports every problem at once.
Surfaces
consoleapi
Intent sources
services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#M1-D3services-crm:docs/milestones/CRM-M1-contacts-and-organizations.plan.md#A16services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#D-07

Controls

18 controls apply, from the corpus control catalogue.

TC-AZ-001 TC-AZ-002 TC-AZ-003 TC-AZ-004 TC-AZ-006 TC-DAT-001 TC-DAT-002 TC-DAT-003 TC-LOG-004 TC-LOG-005 TC-PI-001 TC-PI-002 TC-PI-003 TC-PRV-001 TC-PRV-002 TC-TEN-001 TC-TEN-002 TC-TEN-003

Repositories Read

RepositoryPaths
undefined:modules/entities/
undefined:docs/milestones/CRM-M1-contacts-and-organizations.plan.md
undefined:modules/entities/tests/e2e/organization-types.e2e.spec.js
undefined:modules/entities/tests/e2e/organizations.e2e.spec.js
undefined:modules/entities/tests/integration/db/organizations.table.integration.spec.js
undefined:modules/entities/tests/integration/services/persistence/organizations.field-rules.integration.spec.js
undefined:modules/entities/tests/integration/services/persistence/organizations.integration.spec.js
undefined:modules/entities/tests/unit/db/organization-domain-name.spec.js
undefined:app/(console)/console/[tenantId]/crm/organizations/
undefined:acceptance/crm/playwright/journeys/organizations/CRM-ACC-0100.spec.ts

Where It Lives

Permissions

KeyChecked atScope
crm.organizations.createapitenant
crm.organizations.create-despite-duplicate-blockapitenant
crm.organization-types.readapitenant

Business Rules

12 rules, 11 to be proved before approval. A rule's product intent is derived from its origin: 12 confirmed by a product decision, the rest inheriting this capability's confirmed.

IdRuleKindEnforced atProvenance
01must prove
Confirmed
Organization saves reject blank names, names above 200 characters and notes above 10,000 characters, identifying the invalid field.
✓ Accepted example: a name of exactly 200 characters is accepted.✗ Rejected example: a name of spaces is rejected 400 naming name.
validationapi, service, databasetest
02must prove
Confirmed
Organization creation preserves an unused valid client id within the tenant or generates a time-ordered UUID when none is provided.
validationapi, databasetest
services-crm:modules/entities/tests/e2e/organizations.e2e.spec.js#keeps the id the body named, which is no UUIDv7
03must prove
Confirmed
Organization numbers use a tenant counter separate from contact numbers, initially 10000, ignore client numbers, may leave gaps after refusal and recover collisions above the highest existing organization number.
calculationservice, databasetest
services-crm:modules/entities/tests/integration/services/persistence/organizations.integration.spec.js#renumbers after the tenant's highest organization number, never its contacts'
04must prove
Confirmed
A supplied organization type must exist in the tenant or the save returns a conflict.
validationdatabasetest
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)
05must prove
Confirmed
A parent organization must belong to the same tenant or the save returns a conflict.
validationdatabasetest
services-crm:modules/entities/tests/e2e/organizations.e2e.spec.js#answers 409 for a parent the tenant does not have
06must prove
Confirmed
An organization cannot parent itself or be moved beneath a descendant; when opposite moves race, the move following the first commit is rejected.
✓ Accepted example: a under B under a top: saved.✗ Rejected example: the top moved under its grandchild: 400 naming the parent field.
invariantservice, databasetest
services-crm:modules/entities/tests/integration/db/organizations.table.integration.spec.js#refuses the second move by organizations_parent_not_descendant once the first commits
07must prove
Confirmed
Organization reads compute the nearest-first ancestor chain, its length and its top-level organization, so descendant reads reflect a parent move immediately and supplied ancestry does not control the result.
calculationservicetest
services-crm:modules/entities/tests/integration/services/persistence/organizations.integration.spec.js#answers the descendant, never saved again, its ancestry under the new parent
08must prove
Confirmed
Organization status defaults to active and permits active, inactive or duplicate.
policyapi, databasetest
services-crm:modules/entities/tests/integration/db/organizations.table.integration.spec.js#refuses a status outside the closed list by organizations_status_check
09must prove
Confirmed
An unaccompanied website derives a lowercase domain host without protocol, www, port, path or query, an unaccompanied domain derives an http www website, and an unrecognizable value is preserved without deriving the other field.
calculationservicetest
services-crm:modules/entities/tests/unit/db/organization-domain-name.spec.js#derives the domain name without the protocol or the www prefix
10must prove
Confirmed
An organization logo becomes permanent from a tenant upload, tenant file or public image before the record is written; failure rejects the save and preserves the previous logo.
validationservicetest
11must prove
Confirmed
A blocked organization create requires duplicate-block override authority and a reason rather than confirmation alone.
origin: D-32 (cited in services-crm:aws/crm.service.ts:duplicateBlockOverrideAction)
policyapi, serviceunknown
12
Confirmed
Staff can create organizations in the console, but editing an existing organization uses the API until the Organization 360 milestone delivers its editor.
policyconsoledocumented

Scenarios

IdGivenWhenThenProvenance
01A tenant with a company type.A staff member creates an organization from the console form.The API returns every field as entered, with a number of 10000 or more.test
02A national body, a region below it and a chapter below that.The region moves under another top.The chapter, never saved again, returns its new top level.test
services-crm:modules/entities/tests/integration/services/persistence/organizations.integration.spec.js#answers the descendant, never saved again, its ancestry under the new parent

Edge Cases

IdGivenWhenThenProvenance
03Two administrators move two organizations under each other at the same instant.Both save.The first move commits and the second is rejected.test
services-crm:modules/entities/tests/integration/db/organizations.table.integration.spec.js#refuses the second move by organizations_parent_not_descendant once the first commits

The Markdown files under specs/ in rhythmsoftware/rhythm-v2-docs are the canonical source of truth. This reader is a generated, read-only projection of them.