---
id: DOM-PFM-SEC-002
title: Workspace
realises: CON-PFM-SEC-002
product_area: platform
module: security
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
owned_by: SVC-PFM-SEC-tenants
readable_by:
- SVC-PFM-SEC-security
- SVC-PFM-SEC-customers
lifecycle: STATE-PFM-SEC-001
custom_fields: none
identity: Provisioning uses a readable identifier selected by staff and subject to the customer identifier
  grammar. It remains unique and permanent; the deletion ledger prevents later reuse. Migrated associations
  retain their earlier valid identifier. Workspace-scoped operations address the workspace explicitly.
attributes:
- name: identifier
  kind: text
  required: true
  computed: false
  notes: Selected during provisioning and permanently retired after deletion.
- name: name and acronym
  kind: text
  required: true
  computed: false
  notes: The display name includes the acronym once, without duplicating an existing suffix.
- name: customer
  kind: reference
  required: true
  computed: false
  notes: The customer reference; a parent cannot move to another customer while its sandboxes remain.
- name: parent
  kind: reference
  required: false
  computed: false
  notes: A sandbox’s customer-type parent, belonging to the same customer.
- name: workspace type
  kind: enum
  required: true
  computed: false
  notes: Classification as customer, sandbox, demo, training or support; defaults to customer.
- name: business status
  kind: enum
  required: true
  computed: false
  notes: Staff-controlled classification as implementation, live or disabled, separate from lifecycle readiness.
- name: lifecycle state
  kind: enum
  required: true
  computed: false
  notes: Readiness and destruction state, controlled by lifecycle services and the operator restore exception.
- name: first activation
  kind: date
  required: false
  computed: true
  notes: Provisioning records this once. Loaded-workspace activation preserves the stored value; retirement
    uses its presence in waiting-period selection.
- name: initial load record
  kind: collection
  required: false
  computed: true
  notes: The opening actor, time and reason remain after an initial load finishes.
- name: time zone
  kind: text
  required: true
  computed: false
  notes: The business calendar uses UTC or a recognized Area/Location zone; the default is Eastern time.
- name: commercial company reference
  kind: reference
  required: false
  computed: false
  notes: Provisioning inherits the customer’s commercial reference unless supplied; later changes use the dedicated
    staff operation.
- name: accounting customer reference
  kind: reference
  required: false
  computed: false
  notes: An optional QuickBooks Online customer reference for this workspace.
- name: legacy system, edition and portal settings
  kind: collection
  required: true
  computed: false
  notes: Migration source, edition, currency-display settings and the requested-portal flag; the flag alone
    does not provision a portal.
- name: disposable
  kind: enum
  required: true
  computed: false
  notes: A test-workspace marker allowing the short retirement period outside production.
- name: provisioning jobs
  kind: collection
  required: false
  computed: true
  notes: Durable provisioning submissions and their participant steps.
- name: reset jobs
  kind: collection
  required: false
  computed: true
  notes: Durable, batched jobs for clearing an initial load.
- name: retirement request
  kind: collection
  required: false
  computed: false
  notes: The retained deletion request records reasons, actors, eligibility, holds, notices and its schedule
    and purge jobs. Hold release can extend eligibility.
- name: seed ledger and resource registry
  kind: collection
  required: false
  computed: true
  notes: Participant seeding progress and owned cloud resources, used when repeating or removing work.
- name: staff shortcuts
  kind: collection
  required: false
  computed: false
  notes: Private staff pins and recent-workspace history, limited to twenty pins and ten recent entries.
- name: sender identity
  kind: reference
  required: false
  computed: false
  notes: Notifications owns the sender identity that HQ shows alongside this workspace.
relationships:
- to: DOM-PFM-SEC-001
  cardinality: many workspaces to one customer
  ownership: Each workspace stores one customer reference, which protects that customer from deletion.
  cross_service: false
- to: DOM-PFM-SEC-002
  cardinality: one production workspace to zero or more sandboxes
  ownership: A sandbox stores its parent reference; a customer-type parent may have several sandboxes and cannot
    be retired while they remain.
  cross_service: false
- to: DOM-PFM-SEC-003
  cardinality: one workspace to zero or more portal memberships, workspace-scoped assignments and staff access
    grants
  ownership: Accounts, assignments and grants store their workspace references. Purge removes the portal memberships
    and dependent security records for that workspace.
  cross_service: false
invariants:
- id: INV-DOM-PFM-SEC-002-01
  statement: Workspace identifiers are unique, permanent, readable choices; reserved or generated-shaped values
    and previously deleted identifiers are rejected.
  enforced_at:
  - api
  - service
  - database
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:requireTenantId
- id: INV-DOM-PFM-SEC-002-02
  statement: Only sandboxes have parents. The parent must be a customer-type workspace in the same customer;
    a sandbox cannot itself have children.
  enforced_at:
  - service
  - database
  provenance: test
  source: services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
    a sandbox whose parent belongs to another customer
- id: INV-DOM-PFM-SEC-002-03
  statement: Lifecycle services check the declared transition graph, with an explicit operator restore exception.
    Repeating a state can still change version or timestamps, and ordinary client edits cannot set lifecycle.
  enforced_at:
  - service
  provenance: observed
  source: services-platform:modules/tenants/services/lifecycle/lifecycle-transitions.ts:assertLifecycleTransition;
    modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
- id: INV-DOM-PFM-SEC-002-04
  statement: Deletion-pending and deleting workspaces must be disabled. Loading requires implementation status
    and an opening actor and time.
  enforced_at:
  - database
  provenance: observed
  source: services-platform:modules/tenants/db/tenants.table.ts:tenants (tenants_deletion_pending_status_check,
    tenants_deleting_status_check, tenants_loading_status_check, tenants_loading_entered_check)
- id: INV-DOM-PFM-SEC-002-05
  statement: The service checks that a time zone is recognized; database checks enforce UTC or the permitted
    Area/Location shape and reject Etc zones.
  enforced_at:
  - service
  - database
  provenance: observed
  source: services-platform:modules/tenants/db/tenants.table.ts:tenants (tenants_time_zone_check)
- id: INV-DOM-PFM-SEC-002-06
  statement: Ordinary workspace edits preserve the commercial reference; the dedicated commercial-link operation
    changes it.
  enforced_at:
  - api
  - service
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:setTenantHubspotCompany
- id: INV-DOM-PFM-SEC-002-07
  statement: Ordinary access requires active lifecycle and a business status other than disabled. HQ staff
    routes remain available, with reads only during deletion; loading additionally permits data-job routes.
  enforced_at:
  - service
  provenance: observed
  source: services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailability
- id: INV-DOM-PFM-SEC-002-08
  statement: The database and service allow at most one open retirement request for a workspace.
  enforced_at:
  - service
  - database
  provenance: observed
  source: services-platform:modules/tenants/db/tenant-deletion-requests.table.ts:OPEN_TENANT_DELETION_REQUEST_STATES
- id: INV-DOM-PFM-SEC-002-09
  statement: Later settings do not recalculate a request’s eligibility date. Releasing a hold can extend it
    under the request’s release policy.
  enforced_at:
  - service
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/waiting-period.ts
- id: INV-DOM-PFM-SEC-002-10
  statement: Each destructive purge batch checks that the deleting workspace’s request still names the running
    purge job.
  enforced_at:
  - service
  - database
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/tenant-purge-workflow.ts (header)
- id: INV-DOM-PFM-SEC-002-11
  statement: Reset requires a loading workspace in implementation, typed-identifier confirmation and no other
    open reset.
  enforced_at:
  - service
  provenance: observed
  source: services-platform:modules/tenants/services/reset/reset-tenant.ts:requestTenantReset
- id: INV-DOM-PFM-SEC-002-12
  statement: Repeating a provisioning submission resolves to its existing workspace and job; a different submission
    cannot claim an occupied identifier.
  enforced_at:
  - service
  - database
  provenance: observed
  source: services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts:submitTenantProvisioning
physical:
- platform.tenants
- platform.tenant_provisioning_jobs
- platform.tenant_provisioning_job_steps
- platform.tenant_provisioning_job_events
- platform.tenant_reset_jobs
- platform.tenant_reset_job_steps
- platform.tenant_reset_job_events
- platform.tenant_deletion_requests
- platform.tenant_deletion_notices
- platform.tenant_deletion_schedule_jobs
- platform.tenant_deletion_schedule_job_steps
- platform.tenant_deletion_schedule_job_events
- platform.tenant_purge_jobs
- platform.tenant_purge_job_steps
- platform.tenant_purge_job_events
- platform.tenant_resources
- platform.tenant_seed_applications
- platform.staff_tenant_shortcuts
evidence:
- 'services-platform at ad3f6a65: modules/tenants/db/*.table.ts; services/lifecycle/lifecycle-transitions.ts,
  participants.ts, first-administrator.ts; services/provisioning/*; services/reset/*; services/deletion/*;
  services/access/tenant-availability.ts; services/persistence/tenants.ts, staff-tenant-shortcuts.ts; docs/row-level-security.md
  (customers and tenants are not tenant-owned).'
examined_at: '2026-10-23'
examiner: codex
---

# Workspace

## What It Models

The workspace is an association’s operating environment under one customer. The Workspaces service owns its record and the durable records for provisioning, reset and retirement. Business status expresses the staff decision about use; lifecycle expresses readiness, loading and destruction. They are separate axes with database checks between them.

## Identity and Attributes

Provisioning uses a readable identifier selected by staff and subject to the customer identifier grammar. It remains unique and permanent; the deletion ledger prevents later reuse. Migrated associations retain their earlier valid identifier. Workspace-scoped operations address the workspace explicitly.

The attribute rows distinguish stored fields, computed answers and supporting records.

## Relationships

Each workspace stores one customer reference, which protects that customer from deletion. A sandbox stores its parent reference; a customer-type parent may have several sandboxes and cannot be retired while they remain. Accounts, assignments and grants store their workspace references. Purge removes the portal memberships and dependent security records for that workspace.

## Invariants

The structured invariant rows identify each protection, its enforcement layer and its evidence. Read their qualifications with the statement rather than treating a service check as a database constraint.

## How It Is Stored and Shared

The attribute and relationship rows define the record and its associated work. Sender identity belongs to Notifications. The external deletion ledger is object storage rather than a database table; it retains completed-deletion evidence and prevents identifier reuse after a restore.

## Open Design Questions

Access services enforce the availability invariant. HQ staff retain the documented inspection routes, including during loading, while ordinary customer access follows lifecycle and business status. Loading activation does not record a missing first-activation time; policy depending on that timestamp needs a product decision.

Custom fields have no enabling declaration and are excluded by the product classification. Ownership of participant execution remains a planning question: this service records staff intent and the workspace lifecycle, while participant services execute their own work. Import completion proof, loading retirement and restored-deletion recovery remain open findings.
