---
id: SVC-PFM-SEC-tenants
title: Workspaces Service Module
product_area: platform
module: security
repository: services-platform
source_module: modules/tenants
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
owns:
- DOM-PFM-SEC-002
does_not_own:
- Participants own execution and removal of their resources under the lifecycle protocol; the final module
  boundary remains a planning decision.
- The Data Job Engine owns import runs admitted while loading.
- Licensing owns licenses and application state; commercial-link changes request refresh.
- Notifications owns sender identities, though provisioning writes their selected setting through the shared
  capability.
- Jobs owns durable execution, generic reconciliation and monitoring.
operations:
- operation_id: health
  intent: Return API deployment health and build metadata.
  access: public
  permission: 'none: the shared health route'
  realises: []
  published_to_submissions: 'not published: deployment metadata only.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:healthRoute
- operation_id: enterHqTenantLoading
  route: POST /hq/tenants/{id}/loading
  intent: Open the initial-load lifecycle and retain the staff actor, time and reason.
  access: system
  permission: hq.data-runs.manage
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-loading.routes.ts:enterHqTenantLoading
- operation_id: activateHqTenant
  route: POST /hq/tenants/{id}/activation
  intent: End loading with active lifecycle while preserving business status and first activation.
  access: system
  permission: hq.tenants.activate
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-loading.routes.ts:activateHqTenant
- operation_id: resetHqTenant
  route: POST /hq/tenants/{id}/reset
  intent: Submit a durable participant-batched initial-load reset.
  access: system
  permission: hq.data-runs.manage
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-loading.routes.ts:resetHqTenant
- operation_id: getHqTenantReset
  route: GET /hq/tenants/{id}/reset
  intent: Return the latest reset job and progress for the workspace.
  access: system
  permission: hq.data-runs.manage
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-loading.routes.ts:getHqTenantReset
- operation_id: listMyHqTenantShortcuts
  route: GET /hq/me/tenant_shortcuts
  intent: Return the caller’s private pins and recent-workspace history.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-shortcuts.routes.ts:listMyHqTenantShortcuts
- operation_id: pinMyHqTenantShortcut
  route: PUT /hq/me/tenant_shortcuts/{id}/pin
  intent: Add a workspace to the caller’s limited pin list.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-shortcuts.routes.ts:pinMyHqTenantShortcut
- operation_id: unpinMyHqTenantShortcut
  route: DELETE /hq/me/tenant_shortcuts/{id}/pin
  intent: Remove the caller’s workspace pin.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-shortcuts.routes.ts:unpinMyHqTenantShortcut
- operation_id: recordMyHqTenantShortcutOpened
  route: POST /hq/me/tenant_shortcuts/{id}/opened
  intent: Update the caller’s recent-workspace history.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/hq-tenant-shortcuts.routes.ts:recordMyHqTenantShortcutOpened
- operation_id: listTenantApplicationsForTenant
  route: GET /tenants/{id}/applications
  intent: Return the workspace’s licensed and enabled applications.
  access: console
  permission: platform.tenant-applications.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-applications.routes.ts:listTenantApplicationsForTenant
- operation_id: requestTenantDeletion
  route: POST /tenants/{id}/deletion_requests
  intent: Commit a retirement request with request-time eligibility, notices and a durable watcher.
  access: system
  permission: platform.tenants.deletion-request
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:requestTenantDeletion
- operation_id: listTenantDeletionRequests
  route: GET /tenant_deletion_requests
  intent: Page deletion requests using state and workspace filters.
  access: system
  permission: platform.tenants.deletion-read
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:listTenantDeletionRequests
- operation_id: getTenantDeletionRequest
  route: GET /tenant_deletion_requests/{id}
  intent: Return the retained request, notice outcomes and deletion progress.
  access: system
  permission: platform.tenants.deletion-read
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:getTenantDeletionRequest
- operation_id: holdTenantDeletionRequest
  route: POST /tenant_deletion_requests/{id}/hold
  intent: Pause a scheduled request with a recorded reason.
  access: system
  permission: platform.tenants.deletion-hold
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:holdTenantDeletionRequest
- operation_id: releaseTenantDeletionRequest
  route: POST /tenant_deletion_requests/{id}/release
  intent: Release the hold with eligibility no earlier than three days afterward.
  access: system
  permission: platform.tenants.deletion-hold
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:releaseTenantDeletionRequest
- operation_id: cancelTenantDeletionRequest
  route: POST /tenant_deletion_requests/{id}/cancel
  intent: Close the retirement request before the destructive boundary.
  access: system
  permission: platform.tenants.deletion-cancel
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:cancelTenantDeletionRequest
- operation_id: resumeTenantDeletionSchedule
  route: POST /tenant_deletion_requests/{id}/resume_schedule
  intent: Replace a stopped watcher without changing the retirement decision or eligibility.
  access: system
  permission: platform.tenants.deletion-request
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:resumeTenantDeletionSchedule
- operation_id: retryTenantPurge
  route: POST /tenant_deletion_requests/{id}/retry
  intent: Create a forward retry for a failed request, carrying completed purge steps forward.
  access: system
  permission: platform.tenants.deletion-request
  realises:
  - CAP-PFM-SEC-004
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenant-deletion-requests.routes.ts:retryTenantPurge
- operation_id: createTenant
  route: POST /tenants
  intent: Submit durable provisioning with optional customer, first-administrator and sender creation.
  access: system
  permission: hq.tenants.provision
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:createTenant
- operation_id: getTenantProvisioning
  route: GET /tenants/{id}/provisioning
  intent: Return the workspace’s latest provisioning job and participant progress.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:getTenantProvisioning
- operation_id: retryTenantProvisioning
  route: POST /tenants/{id}/provisioning/retry
  intent: Create a retry for failed provisioning with completed participant steps copied.
  access: system
  permission: hq.tenants.provision
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:retryTenantProvisioning
- operation_id: initializeTenant
  route: POST /tenants/{id}/initialization
  intent: Apply selected participant defaults to an active or failed-provisioning workspace through the seed
    ledger.
  access: system
  permission: hq.tenants.provision
  realises:
  - CAP-PFM-SEC-003
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:initializeTenant
- operation_id: listTenants
  route: GET /tenants
  intent: Return workspaces reachable by the current caller.
  access: console
  permission: platform.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:listTenants
- operation_id: getTenant
  route: GET /tenants/{id}
  intent: Return one workspace within the caller’s reach.
  access: portal
  permission: platform.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:getTenant
- operation_id: updateTenant
  route: PUT /tenants/{id}
  intent: Replace editable workspace fields with record-version comparison and lifecycle/commercial-field protection.
  access: console
  permission: platform.tenants.update
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:updateTenant
- operation_id: patchTenant
  route: PATCH /tenants/{id}
  intent: Apply partial workspace edits with conditional staff status-management checks.
  access: console
  permission: platform.tenants.update (a status change also evaluates platform.tenants.manage-status)
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:patchTenant
- operation_id: setTenantHubspotCompany
  route: PUT /tenants/{id}/hubspot_company
  intent: Change the versioned workspace commercial link and attempt license refresh.
  access: system
  permission: platform.tenants.manage-commercial-link
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:setTenantHubspotCompany
- operation_id: deleteTenant
  route: DELETE /tenants/{id}
  intent: Reject direct deletion and require the retirement-request capability.
  access: system
  permission: hq.tenants.update
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:deleteTenant
- operation_id: getDefaultTenantForCustomer
  route: GET /tenants/default/{customerId}
  intent: Return the customer’s default reachable workspace.
  access: console
  permission: platform.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:getDefaultTenantForCustomer
- operation_id: listByCustomerId
  route: GET /tenants/customer/{customerId}
  intent: Return reachable workspaces belonging to the addressed customer.
  access: console
  permission: platform.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:listByCustomerId
- operation_id: listTenantsByParentId
  route: GET /tenants/parent/{parentId}
  intent: Return visible sandbox children of the addressed workspace.
  access: console
  permission: platform.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:listTenantsByParentId
- operation_id: listHqTenants
  route: GET /hq/tenants
  intent: Search and page HQ workspaces with supported type/status filters and customer names.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:listHqTenants
- operation_id: getHqTenant
  route: GET /hq/tenants/{id}
  intent: Return HQ workspace details including customer, sandboxes and provisioning state.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:getHqTenant
- operation_id: getHqTenantEmailSender
  route: GET /hq/tenants/{id}/email_sender
  intent: Return sender-identity and verification information from Notifications.
  access: system
  permission: hq.tenants.read
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:getHqTenantEmailSender
- operation_id: patchHqTenant
  route: PATCH /hq/tenants/{id}
  intent: Apply supplied HQ workspace edits, requiring separate authority for a changed business status.
  access: system
  permission: hq.tenants.update (a status change also evaluates platform.tenants.manage-status)
  realises:
  - CAP-PFM-SEC-002
  published_to_submissions: 'not published: security or workspace administration, identity handling, or an
    administrative read; no Submissions operation binding is declared.'
  provenance: observed
  source: services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
events:
- name: platform.tenants.provisioning_completed
  direction: produced
  when: Activation attempts a claimed completed-provisioning notification.
  payload_summary: Workspace and customer identity, display name, job identity and destination; no association
    business data.
- name: platform.tenants.provisioning_failed
  direction: produced
  when: Failure settlement attempts a claimed failed-provisioning notification.
  payload_summary: Workspace/customer/job identity plus an operator-safe failure summary.
jobs:
- Provisioning runs dependency-ordered participant work, readiness checks and activation; retry carries completed
  steps and execution is limited to seven days.
- Reset invokes participant batches and retains loading after failure; a new reset continues removal.
- The retirement watcher sends notices and checks the destructive boundary; it can run for a year and stopped
  work requires resume.
- Purge requests flushing, removes participant resources in batches, verifies inventory and finalizes; retry
  carries completed steps.
- Stranded provisioning repair follows job reconciliation and settles bounded failed-job workspaces.
integrations:
- system: Other macroservices' lifecycle functions (CRM and every later domain)
  direction: outbound
  contract: 'Participant lifecycle calls carry identifiers and one declared operation: describe, provision,
    verify, purge, inventory or reset. Live manifests are checked against the job plan.'
- system: Notifications (system notifications and staff e-mail)
  direction: outbound
  contract: Provisioning outcome alerts, requester messages and retirement notices follow committed intent.
    Send and persistence boundaries can cause lost claimed notices or repeated retirement delivery.
- system: Deletion ledger bucket
  direction: outbound
  contract: External versioned deletion evidence holds identities, actors, reasons and counts without member
    data; finalization can complete before ledger writing succeeds.
- system: Licensing
  direction: outbound
  contract: Commercial-link changes request workspace license refresh without a cross-system transaction.
consistency:
- rule: Provisioning commits requested customer/sender creation, workspace and job together before starting
    execution.
  kind: transactional
  compensation: Unstarted work is reconciled to failure and failed provisioning can be retried or retired.
- rule: Participants implement convergent provisioning, reset and purge in planned order.
  kind: eventual
  compensation: 'Recovery proceeds forward: retain partial provisioning, loading reset or deleting purge state
    until the relevant retry succeeds.'
- rule: Retirement intent, notices and watcher commit together; the locked destructive boundary creates purge
    authority atomically.
  kind: transactional
  compensation: Cancellation can return lifecycle to active only before destruction, without enabling business
    status.
- rule: Local invalidation follows lifecycle change; other warm processes can retain availability for thirty
    seconds.
  kind: eventual
  compensation: The availability cache lifetime is the fallback; it is separate from gateway authority caching.
- rule: Finalization completes database deletion before attempting the external restore-detection ledger.
  kind: eventual
  compensation: Task replay can finish outstanding ledger work; restore reapplication uses existing ledger
    entries, so missing entries need operator recovery.
evidence:
- 'services-platform at ad3f6a65: modules/tenants/aws/api/*.routes.ts; services/provisioning/*; services/reset/*;
  services/deletion/*; services/lifecycle/*; services/access/tenant-availability.ts; tenants-notifications.ts;
  aws/logic/*.step-function.ts; docs/jobs.md; docs/tenants/tenant-lifecycle-plan.md; docs/standards/submission-compatible-operations.md.'
examined_at: '2026-10-23'
examiner: codex
controls: [TC-AVL-001, TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, 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-DAT-006, TC-DAT-007, TC-IAM-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-MON-003, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Workspaces Service Module

## What This Service Is For

The Workspaces service owns workspace identity, business status and lifecycle, plus provisioning, loading/reset and retirement requests. Participants own the resources they prepare or remove; generic Jobs owns execution and monitoring.

## Boundary

Participants own execution and removal of their resources under the lifecycle protocol; the final module boundary remains a planning decision. The Data Job Engine owns import runs admitted while loading. Licensing owns licenses and application state; commercial-link changes request refresh. Notifications owns sender identities, though provisioning writes their selected setting through the shared capability. Jobs owns durable execution, generic reconciliation and monitoring.

## Operations in Words

Workspace operations group ordinary/HQ record reads and edits, shortcuts, provisioning and initialization, initial-load/reset/activation, commercial linking and controlled retirement/recovery.

The operation rows describe every declared route, including the direct-delete refusal and the separate commercial-link operation. No route declares a Submissions binding and no module path makes a model inference call.

## Events and Jobs

The declared job inventory covers durable execution and queued background work. Event declarations distinguish actual provisioning notifications from the absence of domain-change events.

## Consistency Guarantees

Durable intent commits before execution starts. Lifecycle availability, gateway authority and provider state have separate consistency bounds. Notification and external ledger effects are not atomic with the owning record.

Retirement remains cancellable until the destructive boundary. Purge recovery moves forward, and finalization can complete the retained request before the ledger succeeds. The module split, initial-import proof and recovery gaps stay recorded as planning disagreements and findings.
