---
id: CAP-PFM-SEC-017
title: Control staff access to customer workspaces
feature: FEAT-PFM-SEC-05
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/hq/rhythm-hq-plan.md#K1'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#K1a'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#K1b'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#K2'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#D2b'
  - 'services-platform:docs/hq/rhythm-hq-plan.md#H3'
  - 'services-platform:docs/security/built-in-policies.md#5 (D-14, Andrew 2026-10-19)'
purpose: >-
  Customer access for Rhythm staff is represented by approved, standing or emergency grants. Customers
  can inspect and revoke these grants independently of HQ staff authority.
outcomes:
  - Staff customer entry has a recorded basis separate from HQ authority.
  - Customer administrators can review and end staff workspace grants.
  - 'Emergency entry includes its reason, ticket, notifications and reporting.'
concepts:
  - CON-PFM-SEC-003
actors:
  - ACT-PFM-004
  - ACT-PFM-005
  - ACT-PFM-001
  - ACT-PFM-006
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: hq.tenant-access.request
    where_checked: api
    scope: global
  - key: hq.tenant-access.read
    where_checked: api
    scope: global
  - key: hq.emergency-access.use
    where_checked: api
    scope: global
  - key: hq.audit.read
    where_checked: api
    scope: global
  - key: hq.tenants.read
    where_checked: api
    scope: global
  - key: platform.staff-access.read
    where_checked: api
    scope: tenant
  - key: platform.staff-access.manage
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-SEC-017-01
    proved_by: [ATS-PFM-SEC-017-01, TST-PFM-SEC-049, TST-PFM-SEC-190]
    statement: >-
      Customer workspace access for staff requires an active staff-access grant and its ordinary role
      assignment. The database rejects a cross-customer staff assignment unless an active grant names it;
      standing grants may cover a whole customer.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#refuses
      a staff member’s tenant-scoped assignment into another customer that no grant names
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1'
  - id: BR-CAP-PFM-SEC-017-02
    proved_by: [ATS-PFM-SEC-017-02, TST-PFM-SEC-049, TST-PFM-SEC-186]
    statement: >-
      An access request names a workspace role, a reason and a duration of one to thirty days. It grants
      no access and notifies workspace administrators. An existing grant prevents another request for
      that workspace.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#materializes
      nothing, so asking grants no access at all
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1'
  - id: BR-CAP-PFM-SEC-017-03
    proved_by: [ATS-PFM-SEC-017-03, TST-PFM-SEC-050, TST-PFM-SEC-062]
    statement: >-
      Viewing and deciding staff access requires the workspace’s staff-access permission. The default
      Security Administrator policy supplies it; Power User and Read Only do not.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/power-user-staff-access.e2e.spec.js#refuses the Power
      User every staff-access route, 403, for the missing key
    origin: 'services-platform:docs/security/built-in-policies.md#5 (D-14, Andrew 2026-10-19)'
  - id: BR-CAP-PFM-SEC-017-04
    proved_by: [ATS-PFM-SEC-017-04, ATS-PFM-SEC-017-14, ATS-PFM-SEC-017-15, TST-PFM-SEC-186]
    statement: >-
      Approval activates access for no more than the requested duration. Decline retains the
      administrator’s reason, withdrawal identifies the requester as decision maker, and each decision
      notifies the staff requester.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#gives
      the two days that were asked for, not the thirty the approver named
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1'
  - id: BR-CAP-PFM-SEC-017-05
    proved_by: [ATS-PFM-SEC-017-05, TST-PFM-SEC-186]
    statement: >-
      An authorized workspace administrator may grant access directly to an identified Rhythm staff
      member. Access starts immediately and notifications go to the member and administrators; an unknown
      staff address is rejected.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#refuses
      an address that belongs to nobody at Rhythm, and writes nothing
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D2'
  - id: BR-CAP-PFM-SEC-017-06
    proved_by: [ATS-PFM-SEC-007-16, ATS-PFM-SEC-017-06, ATS-PFM-SEC-017-17, ATS-PFM-SEC-017-18, TST-PFM-SEC-049, TST-PFM-SEC-186]
    statement: >-
      A workspace administrator may revoke its staff grant. Fresh evaluation then refuses the access,
      although cached decisions can persist. Reconciliation preserves a deliberately revoked standing
      grant.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#leaves
      that standing grant revoked when standing access is ensured again
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1b'
  - id: BR-CAP-PFM-SEC-017-07
    proved_by: [ATS-PFM-SEC-017-07, TST-PFM-SEC-190]
    statement: >-
      Only Rhythm Administrator authority can open emergency access. It requires a workspace role, a
      reason of at least twenty characters, a ticket and a duration no greater than four hours, with no
      extension. Administrators and the staff security list are notified; delivery failure does not undo
      the grant.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#refuses
      a duration past four hours, which is never extended
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K2'
  - id: BR-CAP-PFM-SEC-017-08
    proved_by: [ATS-PFM-SEC-001-14, ATS-PFM-SEC-003-24, ATS-PFM-SEC-016-09, ATS-PFM-SEC-017-08, ATS-PFM-SEC-017-20, ATS-PFM-SEC-017-21, TST-PFM-SEC-186, TST-PFM-SEC-191]
    statement: >-
      The intended standing-access lifecycle gives Rhythm Administrators and founding super users
      customer-level Administrator grants outside Rhythm’s own customer. Role addition and customer
      creation establish them; role removal, suspension, revocation and deletion end them. Existing
      standing access prevents emergency access to that customer. The HQ customer-creation path currently
      omits the reconciliation hook, as recorded in the findings.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/rhythm-administrator-standing-access.integration.spec.js#gives
      each Rhythm Administrator one active customer-level standing grant in every customer but Rhythm’s
      own
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1b'
  - id: BR-CAP-PFM-SEC-017-09
    proved_by: [ATS-PFM-SEC-017-09, TST-PFM-SEC-057, TST-PFM-SEC-066, TST-PFM-SEC-190]
    statement: >-
      Staff may end their own approved or emergency access and submit a cache-flush request. HQ does not
      permit ending standing grants. Another member’s grant is hidden unless a Rhythm Administrator
      manages it from staff detail.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#refuses
      it 409 staff_access_grant_standing, naming the grant
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#H3'
  - id: BR-CAP-PFM-SEC-017-10
    proved_by: [ATS-PFM-SEC-017-10, ATS-PFM-SEC-017-16, TST-PFM-SEC-190]
    statement: >-
      Fresh evaluation denies access after grant expiry; grant reads record its expired state. Explicit
      termination submits a flush request, but existing signed or cached authority may last approximately
      ninety seconds.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#gives
      no access: the evaluator refuses the role’s keys in that tenant over the assignment
    origin: 'services-platform:docs/security/security-administration.md#14 (known bound accepted 2026-10-13)'
  - id: BR-CAP-PFM-SEC-017-11
    proved_by: [ATS-PFM-SEC-017-11, TST-PFM-SEC-049, TST-PFM-SEC-186, TST-PFM-SEC-190]
    statement: >-
      Staff-access events belong to the reached customer’s security history and do not appear in another
      customer’s history. The staff monthly report lists emergency grants opened during the requested
      month.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#never
      shows it on another customer’s trail
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D2b'
  - id: BR-CAP-PFM-SEC-017-12
    proved_by: []
    statement: >-
      HQ workspace role choices include applicable built-ins and that customer’s roles. They exclude
      staff roles and other customers’ roles, and identify roles that currently grant nothing.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/hq-tenant-roles.e2e.spec.js#leaves out another
      customer's custom role and the HQ staff roles
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D2'
  - id: BR-CAP-PFM-SEC-017-13
    proved_by: []
    statement: >-
      The console identifies staff workspace access and its end in a banner. Entry without a grant offers
      emergency access; standing access enters without a dialog and cannot be ended from the banner.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: test
    source: >-
      react-console:e2e/mock/hq-lists.mock.spec.ts#a standing grant cannot be ended from the banner: End
      Access is disabled and Return to HQ leaves
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D2'
  - id: BR-CAP-PFM-SEC-017-14
    proved_by: [ATS-PFM-SEC-017-12, ATS-PFM-SEC-017-19, TST-PFM-SEC-187, TST-PFM-SEC-192]
    statement: >-
      Customer-level standing access permits customer security administration subject to the same
      widening and administrator-lockout checks as customer memberships.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/staff-customer-administration.integration.spec.js#refuses
      staff withdrawing that administrator’s grant, as a lockout
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#K1a'
scenarios:
  - id: SC-CAP-PFM-SEC-017-01
    given: Support needs a workspace investigation for a customer ticket.
    when: A Support Representative requests Read Only for two days and the customer approves.
    then: >-
      The grant permits that workspace’s access until expiry or revocation, with the console banner
      identifying the access.
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/approved-access.e2e.spec.js#is what lets the staff
      member into the tenant, and only then
  - id: SC-CAP-PFM-SEC-017-02
    given: An incident requires customer-workspace action outside business hours.
    when: A Rhythm Administrator opens one hour of emergency access with a reason and ticket.
    then: >-
      Notifications go to customer administrators and the grant is included in the report for its opening
      month.
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js#e-mails
      each of the tenant’s administrators who, which tenant, which role, why, the ticket and until when
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-PFM-SEC-007
  - CAP-PFM-SEC-010
  - CAP-PFM-SEC-016
  - CAP-PFM-SEC-001
journeys:
  - JNY-PFM-SEC-005
open_questions: []
evidence:
  - >-
    Pinned services-platform references for the structured rows: docs/hq/rhythm-hq-plan.md;
    docs/security/built-in-policies.md; docs/security/security-administration.md;
    modules/security/tests/e2e/approved-access.e2e.spec.js;
    modules/security/tests/e2e/hq-tenant-roles.e2e.spec.js;
    modules/security/tests/e2e/power-user-staff-access.e2e.spec.js;
    modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js;
    modules/security/tests/integration/services/staff-access/open-emergency-access.integration.spec.js;
    modules/security/tests/integration/services/staff-access/rhythm-administrator-standing-access.integration.spec.js;
    modules/security/tests/integration/services/staff-access/staff-customer-administration.integration.spec.js.
  - 'Pinned react-console references for the structured rows: e2e/mock/hq-lists.mock.spec.ts.'
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, 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-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, 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-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-SEC-05-01, FAS-PFM-SEC-05-02, FAS-PFM-SEC-05-03, FAS-PFM-SEC-05-04, FAS-PFM-SEC-05-05]
suites: [TST-PFM-SEC-049, TST-PFM-SEC-050, TST-PFM-SEC-057, TST-PFM-SEC-062, TST-PFM-SEC-066, TST-PFM-SEC-186, TST-PFM-SEC-187, TST-PFM-SEC-190, TST-PFM-SEC-191, TST-PFM-SEC-192]
---
# Control staff access to customer workspaces

## Purpose

Customer access for Rhythm staff is represented by approved, standing or emergency grants. Customers can inspect and revoke these grants independently of HQ staff authority.

## How It Works

A staff operator asks for a workspace role and duration from HQ and waits for a customer decision. The customer administrator reviews that request in Rhythm Access or gives access directly. After a grant is active, the operator enters the workspace with a banner describing the staff access. Standing access and emergency entry follow separate paths, while revocation remains visible to the customer. Ending the grant changes stored assignments and fresh evaluation; previously issued authority remains subject to its cache and signature expiry. The product should reconcile the customer-creation paths that differ in establishing standing access.

## Relationships

- Role assignment supplies the usable customer authority.
- Security context reports the reachable workspaces.
- HQ staff administration manages the memberships holding the grants.
