---
id: CAP-PFM-TNL-001
title: Request a complete customer workspace
feature: FEAT-PFM-TNL-01
product_area: platform
module: tenant-lifecycle
revision: 2
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
intent_sources:
  - 'services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#§I'
  - 'services-platform:docs/tenants/tenant-identity.md#The rules'
purpose: >-
  Staff submit a workspace request that Rhythm carries through the participating
  applications.
outcomes:
  - >-
    Customer creation when needed, workspace creation and job recording succeed
    together.
  - A repeated submission retains the original workspace and job.
  - The new workspace stays closed during construction.
concepts:
  - CON-PFM-TNL-002
  - CON-PFM-TNL-001
actors:
  - ACT-PFM-004
  - ACT-PFM-012
surfaces:
  - console
  - api
  - job
preconditions: []
postconditions: []
permissions:
  - key: hq.tenants.provision
    where_checked: api
    scope: global
rules:
  - id: BR-CAP-PFM-TNL-001-01
    proved_by: [ATS-PFM-TNL-001-01, TST-PFM-TNL-056]
    statement: >-
      Provisioning requests require Rhythm staff authority and the provisioning
      permission; customer administrators cannot create a workspace this way.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may
      not ask for a tenant at all
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#§H1 (approved 2026-10-11)'
  - id: BR-CAP-PFM-TNL-001-02
    proved_by: [ATS-PFM-TNL-001-02, TST-PFM-TNL-057]
    statement: >-
      Staff supply a readable workspace identifier; omitted, generated-looking
      and reserved identifiers are rejected.
    kind: validation
    enforced_at:
      - api
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a
      create that names no id as 400 tenant_id_required, naming id
    origin: >-
      services-platform:docs/tenants/tenant-identity.md#The rules (Andrew,
      2026-10-17)
  - id: BR-CAP-PFM-TNL-001-03
    proved_by: [ATS-PFM-TNL-001-03, TST-PFM-TNL-082]
    statement: >-
      Resubmitting the same submission returns its original workspace and job
      without creating another of either.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
      the same tenant and the same job when the same submission is sent twice
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1 (approved
      2026-10-09)
  - id: BR-CAP-PFM-TNL-001-04
    proved_by: [ATS-PFM-TNL-001-04]
    statement: >-
      A new submission cannot claim an identifier already assigned to a
      workspace, and the refusal identifies the collision.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
      a different submission that names a tenant id somebody already has
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1 (approved
      2026-10-09)
  - id: BR-CAP-PFM-TNL-001-05
    proved_by: [ATS-PFM-TNL-001-05, TST-PFM-TNL-085]
    statement: >-
      Creation of a new customer when needed, its workspace, the sender setting
      and the provisioning job commits together; a rejected request retains none
      of those writes.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
      no tenant at all when the strategy is refused: the request is rejected
      whole
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1 (approved
      2026-10-09)
  - id: BR-CAP-PFM-TNL-001-06
    proved_by: [ATS-PFM-TNL-001-06, ATS-PFM-TNL-001-09, TST-PFM-TNL-056]
    statement: >-
      A requested workspace begins closed in provisioning and becomes usable
      after the build succeeds.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers
      a tenant that is not usable yet, because the work has only been asked for
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1, §4.5
      (approved 2026-10-09)
  - id: BR-CAP-PFM-TNL-001-07
    proved_by: [ATS-PFM-TNL-001-07, TST-PFM-TNL-082]
    statement: >-
      Job execution starts after the request commits; a failed start leaves the
      committed workspace and pending job for reconciliation.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#leaves
      the job pending and without a handle, which is what the reconciler settles
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1 (approved
      2026-10-09)
  - id: BR-CAP-PFM-TNL-001-08
    proved_by: []
    statement: >-
      The database permits no more than one pending or running provisioning job
      for a workspace.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    provenance: observed
    source: >-
      services-platform:modules/tenants/db/tenant-provisioning-jobs.table.ts:tenant_provisioning_jobs_open_uidx
    origin: >-
      services-platform:docs/hq/rhythm-hq-plan.md#§I Concurrency (approved
      2026-10-11)
  - id: BR-CAP-PFM-TNL-001-09
    proved_by: []
    statement: >-
      Provisioning opens the workspace with the requested live or implementation
      status, defaulting to implementation.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: false
    provenance: observed
    source: >-
      services-platform:modules/tenants/db/tenant-provisioning-jobs.table.ts:DEFAULT_PROVISIONED_TENANT_STATUS
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#§D10 (approved 2026-10-11)'
  - id: BR-CAP-PFM-TNL-001-10
    proved_by: [ATS-PFM-TNL-001-08, TST-PFM-TNL-086]
    statement: >-
      Omitting the commercial company inherits the customer’s company;
      explicitly clearing it leaves the workspace without that link.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: >-
      services-platform:docs/tenants/console-contract.md#The HubSpot company
      link
    origin: none
scenarios:
  - id: SC-CAP-PFM-TNL-001-01
    given: A staff member submits a form twice.
    when: Both copies reach provisioning.
    then: Both responses identify the single recorded workspace and job.
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
      the same tenant and the same job when the same submission is sent twice
  - id: SC-CAP-PFM-TNL-001-02
    given: An existing association holds the requested identifier.
    when: Staff submit a different request for that identifier.
    then: The response rejects the identifier collision.
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an
      id another tenant has as 409 tenant_id_taken
edge_cases: []
constraints: []
depends_on:
  - CAP-PFM-TNL-007
related:
  - CAP-PFM-TNL-002
  - CAP-PFM-TNL-003
  - CAP-PFM-TNL-004
  - CAP-PFM-TNL-018
journeys:
  - JNY-PFM-TNL-001
open_questions: []
evidence:
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1
  - 'Inspected source: services-platform:docs/hq/rhythm-hq-plan.md#§I'
  - >-
    Inspected source: services-platform:docs/tenants/tenant-identity.md#The
    rules
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may
    not ask for a tenant at all
  - >-
    Inspected source: services-platform:docs/hq/rhythm-hq-plan.md#§H1 (approved
    2026-10-11)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a
    create that names no id as 400 tenant_id_required, naming id
  - >-
    Inspected source: services-platform:docs/tenants/tenant-identity.md#The
    rules (Andrew, 2026-10-17)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
    the same tenant and the same job when the same submission is sent twice
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1 (approved
    2026-10-09)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
    a different submission that names a tenant id somebody already has
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
    no tenant at all when the strategy is refused: the request is rejected whole
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers
    a tenant that is not usable yet, because the work has only been asked for
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§4.1, §4.5 (approved
    2026-10-09)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#leaves
    the job pending and without a handle, which is what the reconciler settles
  - >-
    Inspected source:
    services-platform:modules/tenants/db/tenant-provisioning-jobs.table.ts:tenant_provisioning_jobs_open_uidx
  - >-
    Inspected source: services-platform:docs/hq/rhythm-hq-plan.md#§I Concurrency
    (approved 2026-10-11)
  - >-
    Inspected source:
    services-platform:modules/tenants/db/tenant-provisioning-jobs.table.ts:DEFAULT_PROVISIONED_TENANT_STATUS
  - >-
    Inspected source: services-platform:docs/hq/rhythm-hq-plan.md#§D10 (approved
    2026-10-11)
  - >-
    Inspected source: services-platform:docs/tenants/console-contract.md#The
    HubSpot company link
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an
    id another tenant has as 409 tenant_id_taken
controls: [TC-AVL-001, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-003, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-PI-001, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-TNL-01-01, FAS-PFM-TNL-01-02, FAS-PFM-TNL-01-04, FAS-PFM-TNL-01-05]
suites: [TST-PFM-TNL-056, TST-PFM-TNL-057, TST-PFM-TNL-082, TST-PFM-TNL-085, TST-PFM-TNL-086]
---

# Request a complete customer workspace

## Purpose

Staff submit a workspace request that Rhythm carries through the participating applications.

## How It Works

A Rhythm administrator supplies the workspace identifier, name and customer. The request can also name the opening business status, a first administrator for a new customer and an e-mail sender. Rhythm records the request and build job together. A duplicate submission returns the recorded result. A conflicting identifier produces a refusal instead. After the transaction commits, the job starts the application work. If execution cannot start immediately, the committed job remains available to reconciliation. Staff follow the build separately while customer access remains closed.

## Relationships

- Account for each application’s lifecycle responsibilities: Participant declarations establish which application areas the build must reach.
- Open a workspace after its applications are ready: Its readiness and activation finish workspace construction.
- Understand and recover a workspace build: Its snapshots and recovery explain interrupted construction.
- Prepare the customer’s first access and sender: Its first-administrator and sender setup use the recorded creation choices.
- Retain deletion evidence and prevent identifier reuse: Retired identifiers and retained removal history also constrain this work.
