---
id: CAP-PFM-SEC-003
title: Prepare a workspace for customer use
feature: FEAT-PFM-SEC-01
product_area: platform
module: security
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-platform:docs/tenants/tenant-lifecycle-plan.md#4. Provisioning'
  - 'services-platform:docs/tenants/tenant-lifecycle-plan.md#13 (D3)'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#I. Provisioning workflow'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#K3'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#K8'
  - 'services-platform:docs/tenants/tenant-identity.md#The rules (Andrew, 2026-10-17)'
purpose: >-
  Rhythm staff coordinate workspace setup and initial data loading, with progress and recovery available
  through HQ.
outcomes:
  - Staff follow setup across participating services before handover.
  - Failed setup retains completed work for a later retry.
  - 'Initial loading, reset and activation support preparation before a separate go-live decision.'
concepts:
  - CON-PFM-SEC-002
  - CON-PFM-SEC-001
actors:
  - ACT-PFM-004
  - ACT-PFM-005
  - ACT-PFM-006
surfaces:
  - console
  - api
  - job
preconditions: []
postconditions: []
permissions:
  - key: hq.tenants.provision
    where_checked: api
    scope: global
  - key: hq.tenants.read
    where_checked: api
    scope: global
  - key: hq.tenants.activate
    where_checked: api
    scope: global
  - key: hq.data-runs.manage
    where_checked: api
    scope: global
rules:
  - id: BR-CAP-PFM-SEC-003-01
    proved_by: [ATS-PFM-SEC-003-01, TST-PFM-SEC-229]
    statement: >-
      Provisioning, progress reads, retries and initialization require staff authority; customer
      administrators cannot perform them even for their own workspace.
    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#D1'
  - id: BR-CAP-PFM-SEC-003-02
    proved_by: [ATS-PFM-SEC-003-02, TST-PFM-SEC-230, TST-PFM-SEC-265]
    statement: >-
      Provisioning requires a chosen readable slug of 1–64 lowercase characters with alphanumeric ends
      and no adjacent dots, generated-identifier shape, reserved value, existing value or retired
      workspace identifier; a new customer uses the same slug validation.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an id another tenant has as
      409 tenant_id_taken
    origin: 'services-platform:docs/tenants/tenant-identity.md#The rules (Andrew, 2026-10-17)'
    examples:
      positive: A production identifier and a distinct sandbox identifier pass validation.
      negative: A generated-identifier shape fails with the invalid-identifier code.
  - id: BR-CAP-PFM-SEC-003-03
    proved_by: [ATS-PFM-SEC-001-13, ATS-PFM-SEC-003-03, ATS-PFM-SEC-003-20, TST-PFM-SEC-258]
    statement: >-
      Replaying a submission returns its original workspace and job, while a distinct submission using an
      occupied workspace identifier fails.
    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 Contract for asking'
  - id: BR-CAP-PFM-SEC-003-04
    proved_by: [ATS-PFM-SEC-003-04, ATS-PFM-SEC-003-15, ATS-PFM-SEC-003-24, TST-PFM-SEC-229, TST-PFM-SEC-258]
    statement: >-
      Workspace activation follows provisioning and readiness confirmation from every enabled participant
      and records the activation time.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#asks
      every participant to confirm what it made before the tenant is opened
    origin: 'services-platform:docs/tenants/tenant-lifecycle-plan.md#4.5 Ready means'
  - id: BR-CAP-PFM-SEC-003-05
    proved_by: [ATS-PFM-SEC-003-05, ATS-PFM-SEC-003-16, ATS-PFM-SEC-003-17, ATS-PFM-SEC-003-22, ATS-PFM-SEC-004-26, TST-PFM-SEC-229, TST-PFM-SEC-258]
    statement: >-
      Failed provisioning preserves completed work and marks the workspace failed; retries are permitted
      only from that state and resume unfinished work.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
      the missing work and not the finished work when it is provisioned again
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#4.4 Partial failure, compensation, external
      success
  - id: BR-CAP-PFM-SEC-003-06
    proved_by: [ATS-PFM-SEC-003-06, ATS-PFM-SEC-003-23, TST-PFM-SEC-258]
    statement: >-
      A provisioning request creating a customer with a first administrator sends one customer-wide
      Administrator invitation and records it to prevent a second invitation on retry.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
      not invite them a second time when the provisioning is run again
    origin: 'services-platform:docs/tenants/tenant-lifecycle-plan.md#4.3 Participants at launch'
  - id: BR-CAP-PFM-SEC-003-07
    proved_by: [ATS-PFM-SEC-003-07, TST-PFM-SEC-228, TST-PFM-SEC-259]
    statement: >-
      Provisioning sends the requester an outcome e-mail and publishes an operations alert with the job
      link without repeating delivered notices; notice failure does not turn the provisioning job into a
      failure.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#sends
      nothing a second time when the activate task runs again
    origin: 'services-platform:docs/tenants/tenant-lifecycle-plan.md#4.6 The requester is told how it ended'
  - id: BR-CAP-PFM-SEC-003-08
    proved_by: [ATS-PFM-SEC-003-08, TST-PFM-SEC-261]
    statement: >-
      Sender setup validates domain or address strategies before creating a workspace; a supplied address
      must match a supplied domain, domain values must be hostnames, and an omitted domain can use a
      hostname-shaped workspace identifier.
    kind: validation
    enforced_at:
      - api
      - service
    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/hq/rhythm-hq-plan.md#K3'
  - id: BR-CAP-PFM-SEC-003-09
    proved_by: []
    statement: >-
      Pending sender verification does not block activation; the shared Rhythm sender remains available
      until the customer publishes the required records.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#opens
      the tenant anyway, which is what option A promises
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K3'
  - id: BR-CAP-PFM-SEC-003-10
    proved_by: []
    statement: >-
      Provisioning inherits the customer’s commercial account unless the request explicitly selects a
      different account or no account.
    kind: calculation
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts:resolveHubspotCompanyId
    origin: none
  - id: BR-CAP-PFM-SEC-003-11
    proved_by: [ATS-PFM-SEC-003-09, TST-PFM-SEC-260]
    statement: >-
      Reconciliation moves a still-provisioning workspace behind a settled failed job to provisioning
      failure and records its outcome notice without repeating a delivered notice.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
      the stranded tenant to provisioning_failed, which makes it retryable and deletable again
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#4.4 Partial failure, compensation, external
      success
  - id: BR-CAP-PFM-SEC-003-12
    proved_by: [ATS-PFM-SEC-003-10, TST-PFM-SEC-229, TST-PFM-SEC-255]
    statement: >-
      Initialization rejects missing workspaces, unknown participants and workspaces whose deletion is
      pending or underway.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
      a participant that is not in the registry, and names the ones that are
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#6.5 Initialization for capabilities added
      later
  - id: BR-CAP-PFM-SEC-003-13
    proved_by: [ATS-PFM-SEC-002-22, ATS-PFM-SEC-003-11, ATS-PFM-SEC-003-18, ATS-PFM-SEC-003-21, TST-PFM-SEC-220]
    statement: >-
      Initial loading requires implementation status, records the initiating person and reason, and
      blocks ordinary customer work during the import.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a live tenant, an
      initial import going only into an implementation tenant
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K8'
  - id: BR-CAP-PFM-SEC-003-14
    proved_by: [ATS-PFM-SEC-003-12, TST-PFM-SEC-220, TST-PFM-SEC-263]
    statement: >-
      Reset requires a loading workspace, an exact identifier confirmation, reset support from every
      required participant and no running reset; it preserves configuration and returns the workspace to
      loading.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js#refuses
      a confirmation that is not the tenant’s id, and does not say what to type
    origin: none
  - id: BR-CAP-PFM-SEC-003-15
    proved_by: [ATS-PFM-SEC-003-13, ATS-PFM-SEC-003-19, TST-PFM-SEC-220]
    statement: >-
      Activation requires authority separate from import execution and restores ordinary availability
      while leaving business status unchanged.
    kind: permission
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff member
      who ran the import, activation being the other key
    origin: none
scenarios:
  - id: SC-CAP-PFM-SEC-003-01
    given: An association is preparing a migrated workspace.
    when: Staff provision its production workspace and a sandbox under the same customer.
    then: >-
      Both retain their chosen identifiers, and the sandbox can be selected by its identifier in security
      context.
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#creates the sandbox
      sandbox.rubber.org under it
  - id: SC-CAP-PFM-SEC-003-02
    given: A setup participant has failed.
    when: Staff start a retry and subsequently read progress.
    then: >-
      The retry uses a new job, reaches readiness when work succeeds and becomes the latest provisioning
      snapshot.
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers the retry’s job
      to a reader afterwards, which is the latest provisioning
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-PFM-SEC-001
  - CAP-PFM-SEC-002
  - CAP-PFM-SEC-004
  - CAP-PFM-SEC-008
  - CAP-PFM-SEC-017
journeys:
  - JNY-PFM-SEC-001
open_questions:
  - OQ-PFM-SEC-001
evidence:
  - >-
    Pinned services-platform references for the structured rows: docs/hq/rhythm-hq-plan.md;
    docs/tenants/tenant-identity.md; docs/tenants/tenant-lifecycle-plan.md;
    modules/tenants/services/provisioning/submit-tenant-provisioning.ts;
    modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js;
    modules/tenants/tests/e2e/tenants.e2e.spec.js;
    modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js;
    modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js.
controls: [TC-AVL-001, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CHG-005, TC-CHG-006, TC-CHG-007, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, TC-LOG-001, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-004, 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-SEC-01-01, FAS-PFM-SEC-01-02, FAS-PFM-SEC-01-04, FAS-PFM-SEC-01-05]
suites: [TST-PFM-SEC-220, TST-PFM-SEC-228, TST-PFM-SEC-229, TST-PFM-SEC-230, TST-PFM-SEC-255, TST-PFM-SEC-258, TST-PFM-SEC-259, TST-PFM-SEC-260, TST-PFM-SEC-261, TST-PFM-SEC-263, TST-PFM-SEC-265]
---
# Prepare a workspace for customer use

## Purpose

Rhythm staff prepare the association’s workspace and follow the work needed before customer use. A visible job connects the request, progress and recovery without requiring staff to keep the setup screen open.

## How It Works

Staff begin in the HQ provisioning wizard and choose the customer and workspace details. They can include sender setup and a first administrator when establishing a customer. Submission opens a job page where staff inspect progress and any failure explanation. Participating services contribute their setup work and readiness responses. If setup fails, staff use the job information to choose recovery rather than submit a competing workspace request. A retry continues the retained setup. For a migration, staff separately open initial loading and run the required data work. Reset supports another import attempt while retaining workspace configuration. The activation action requires its own permission; the same person may hold both import and activation permissions. Business go-live remains a separate decision, and the missing import-completion check is recorded as debt.

## Relationships

- Customer creation supplies the owning account for a new workspace.
- Invitation handling establishes the initial administrator.
- Staff-access reconciliation supplies standing access where applicable.
- The lifecycle module owns participant protocols; the data job engine and operations module provide import execution and job presentation.
