# Verixa — User Requirements Specification

# Module 1: Authentication, Session Management & Access Control

| Field | Value |
|---|---|
| Document ID | VRX-URS-01 |
| Version | 1.0 |
| Status | Final — ready for QA, Validation, Regulatory Affairs, Information Security, and Founder approval. URS approval is separate from validation execution. This document becomes "Approved Controlled URS — released for engineering implementation and validation planning" only after signature capture in the Document Approval block. It becomes "Released for validation execution" only after the module migration evidence gate (URS-01-VAL-008) and validation evidence pack are satisfied. |
| Document Type | User Requirements Specification (URS) |
| GAMP 5 Category | Category 5 — Custom Application |
| Regulatory Classification | Critical infrastructure substrate for 21 CFR Part 11 / EU GMP Annex 11 across the Verixa platform |
| Date of Issue | 2026-05-05 |
| Module Owner (Engineering) | Platform / Identity Squad |
| Module Owner (Quality Validation) | CSV / CSA Lead — Authentication & Authority |
| Module Owner (Compliance) | Quality Assurance, Regulatory Affairs |
| Approving Authority | Founder / Chairman & MD (overall); QA Head, Validation Head, RA Head, Information Security Head (functional) |

## Document Approval

| Role | Name | Signature | Date |
|---|---|---|---|
| Author — Platform Architecture | _____________________ | _____________________ | __________ |
| Reviewer — Engineering Lead | _____________________ | _____________________ | __________ |
| Reviewer — QA / Validation Lead | _____________________ | _____________________ | __________ |
| Reviewer — Information Security Lead | _____________________ | _____________________ | __________ |
| Reviewer — Regulatory Affairs Lead | _____________________ | _____________________ | __________ |
| Approving Authority — Founder, Chairman & MD | _____________________ | _____________________ | __________ |

## Version History

| Version | Date | Summary |
|---|---|---|
| 1.0 | 2026-05-05 | First issued user requirements specification for Module 1. |

---

## 0. Document Framing

### 0.1 Purpose of this document

This URS defines the target expected state for Verixa's Authentication, Session Management & Access Control module (Module 1). It is the binding contract between product, engineering, quality validation, regulatory affairs, information security, and the executive authority for the design, implementation, validation, release, and on-going periodic review of this module. Compliance with this URS is mandatory.

### 0.2 Audience

- Engineering — design, implementation, code review.
- Quality Assurance / Validation — IQ / OQ / PQ test design, traceability matrix, validation reports.
- Regulatory Affairs — regulatory mapping, inspection readiness.
- Information Security — security review, penetration testing, incident response.
- Product Owners — feature definition, UX acceptance.
- Inspectors and Auditors (FDA, EU GMP / MHRA, CDSCO, ISO, customer audits, internal audits) — evidence of system intent and controls.
- Customers — confirmation of platform behaviour during qualification of Verixa as a supplier.

### 0.3 Reading conventions

- Requirements use the keywords MUST, SHOULD, and MAY as defined in IETF RFC 2119 / RFC 8174.
- Each atomic requirement carries an identifier of the form `URS-01-<Domain>-<Number>`, where `<Domain>` is one of `FE` (front-end), `BE` (back-end), `WF` (workflow), `DATA` (data model), `SEC` (security), `AUD` (audit), `ESIG` (electronic signature), `AI` (AI / human-in-the-loop), `INT` (integration), `REP` (reports / exports), or `VAL` (validation evidence).
- Supporting identifiers: `DEC-01-<N>` (closed launch decision), `DEC-01-<N>` (closed launch decision), `DEP-01-<N>` (dependency), `BR-01-<N>` (business rule), `RG-01-<N>` (regulatory mapping row), `TC-PLAIN-<N>` (plain-language test scenario), `TC-TECH-<N>` (technical test case), `AC-01-<N>` (acceptance criterion in Given/When/Then), `CIM-<N>` (change-impact matrix row).
- Where this document does not state a fact in §18.1, the absence MUST be treated as a defect to be recorded under Dependencies or Validation Evidence Gates. The text never substitutes invention for evidence.

### 0.4 Inherited cross-module standards

These twelve standards apply to Module 1 and to every other Verixa module. They are listed once here.

1. **Three-layer guard hierarchy on the front end.** `<RoleGuard>` controls page / module access by base role. `<PermissionGuard>` controls fine-grained role × resource × action permissions. `<AuthorityGuard>` controls regulated-decision eligibility (approve, release, dispose, sign off, delegate, override, closure, final review). Guards are nested in that order. `<PermissionGuard>` alone is insufficient for any regulated decision. `<AuthorityGuard>` is advisory; the back end is always authoritative.
2. **Controlled Approval Modal contract.** Every regulated approval, closure, void, release, certification, or final-review action routes through a single shared modal that collects exactly: re-authentication password, meaning of signature, and reason for change. The front end NEVER sends `ip`, `userAgent`, `timestamp`, or `performedBy` in the request body. The back end derives these from the authenticated request context. Any client-supplied attribution field is silently dropped server-side.
3. **API path discipline.** Front-end calls relative paths via the configured API client; never hard-coded `/api/` or `/api/v1/` prefixes. Generic `PATCH /entity/:id` is forbidden for compliance state transitions. Explicit action endpoints are required (for example `POST /capas/:id/approve`).
4. **Tenant isolation.** Every database operation routes through the Tenant Data Access Layer with tenant context bound to the connection. Every table has Row-Level Security enabled in the same migration that creates it. Cross-tenant operations route through the explicit platform-context API only where documented and approved.
5. **Audit trail.** Every INSERT, UPDATE, DELETE, soft-delete, void, restore, signature, override, AI suggestion, AI acceptance / rejection, integration event, export, archive, and permission change MUST emit an audit-trail entry with tenant, actor, role, server-clock timestamp, action, resource type, resource id, record version, before / after state, reason for change (where applicable), source IP, user agent, session id, correlation id, and electronic signature id where linked. **Audit-log write failure rolls back the originating action.** No state change without an audit row.
6. **ALCOA+ universal compliance.** Every module satisfies all nine principles: Attributable, Legible, Contemporaneous, Original, Accurate, Complete, Consistent, Enduring, Available. Section 13 of each module URS provides the principle-to-control mapping.
7. **Fail-secure on resolver failure.** When the Authority Resolver cannot return an authority context, the relevant API responds with HTTP `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` carrying a correlation identifier. The user remains authenticated for read-only paths. The user interface surfaces a persistent banner ("Authority context unavailable — approval actions temporarily disabled") and `<AuthorityGuard>` renders disabled buttons with the same tooltip.
8. **Claims-version mismatch.** Every issued JSON Web Token carries a claims version. Every session row carries the same value. On token refresh, a mismatch combined with a regulated authority change triggers session revocation and `401 SESSION_REVOKED_AUTHORITY_CHANGE`.
9. **No optimistic updates on regulated actions.** Approvals, closures, voids, releases, signatures, MFA enrolment, password changes, session revocations, role changes, and authority management actions never use optimistic UI. The UI waits for the definitive 2xx response before reflecting state.
10. **AI is suggestion-only, never actor.** AI may classify, summarise, draft, prioritise, or recommend. AI MUST never approve, close, release, certify, sign, or submit a regulated record without explicit authorised human action through the Controlled Approval Modal and electronic signature. In critical Good Manufacturing Practice functions (batch release, OOS / OOT classification, deviation classification, CAPA disposition), generative or probabilistic AI is prohibited.
11. **Document Quality Gateway interception.** Every regulated document write (creation, revision, supersession) routes through the Document Quality Gateway (Module 31). Direct write to a controlled document store is forbidden unless explicitly exempted in writing.
12. **Encryption discipline.** Secrets at rest are encrypted using the cloud Key Management Service with managed-key rotation at least annually. Transport security uses TLS 1.2 or higher with HTTP Strict Transport Security preload and ciphers per current OWASP guidance. Logs scrub passwords, tokens, MFA secrets, and SSO secrets.

#### Diagram 0.4-A — Three-layer guard decision flow (front end and back end)

```mermaid
flowchart TD
  A([User invokes a regulated UI control]) --> B{RoleGuard:<br/>does base role<br/>permit module access?}
  B -- No --> X1[Render &lt;AccessDenied/&gt;<br/>no API call issued]
  B -- Yes --> C{PermissionGuard:<br/>does RBAC allow<br/>resource × action?}
  C -- No --> X2[Render &lt;AccessDenied/&gt;<br/>no API call issued]
  C -- Yes --> D{AuthorityGuard:<br/>does authzContext carry<br/>required Authority Profile<br/>or active Delegation in scope?}
  D -- Context null --> X3[Disabled button +<br/>tooltip 'Authority<br/>context unavailable']
  D -- Profile missing --> X4[Disabled button +<br/>tooltip 'Requires<br/>{profile} authority']
  D -- Yes --> E[Enabled button]
  E --> F[User clicks → Controlled Approval Modal]
  F --> G[POST regulated action]
  G --> H{Backend pipeline:<br/>authenticate → tenant → rbac<br/>→ contextGate → workflow<br/>→ authorityCheckHook}
  H -- Any deny --> X5[403 with specific code<br/>e.g. AUTHORITY_CHECK_FAILED]
  H -- All pass --> I[Action committed +<br/>audit + electronic signature linked]
```

### 0.5 Verixa URS suite — module map

This document is one of thirty-five modules in the Verixa launch URS suite. Cross-module references in this document use the module number and short title shown below.

| Module | Title |
|---|---|
| URS-01 | Authentication, Session Management & Access Control (this document) |
| URS-02 | Role-Based Access Control & Permissions |
| URS-03 | Context Gate & Approval Scope |
| URS-04 | Workflow / Human-in-the-Loop / Electronic Signature / Approval Authority |
| URS-05 | Authority Profile / Approval Delegation / Segregation of Duties |
| URS-06 | Audit Trail & Data Integrity |
| URS-07 | Study Management |
| URS-08 | Tenant Management |
| URS-09 | Sites Management |
| URS-10 | Products Management |
| URS-11 | Supplier Management |
| URS-12 | Document Control & Knowledge Libraries |
| URS-13 | Regulated change governance |
| URS-14 | Complaints |
| URS-15 | Out-of-Specification / Out-of-Trend |
| URS-16 | Deviations |
| URS-17 | Root Cause Analysis |
| URS-18 | Corrective and Preventive Actions |
| URS-19 | Risk Assessment |
| URS-20 | Reviews |
| URS-21 | Findings |
| URS-22 | Inspection Management & Readiness |
| URS-23 | Batch Records & Manufacturing Execution |
| URS-24 | Stability Management |
| URS-25 | Environmental Monitoring |
| URS-26 | Annual Product Quality Review |
| URS-27 | Regulatory Intelligence & Submission Governance |
| URS-28 | Training Management & Qualification |
| URS-29 | Screen Reader / Data Capture & Extraction Governance |
| URS-30 | Notifications, Delivery Channels & Communication Governance |
| URS-31 | Document Quality Gateway |
| URS-32 | MIRA AI Chat / Command Center / Agent Orchestration |
| URS-33 | Good Manufacturing Practice — Manufacturing Operations & Controls |
| URS-34 | Good Distribution Practice — Distribution, Warehouse & Dispatch Controls |
| URS-35 | Infrastructure, Backup, Restore & Operational Resilience |

### 0.6 Glossary

This glossary defines every domain term used in this URS in plain language. Where the term anchors to a regulatory clause, the clause is named.

#### Identity, session, and authority

- **Authentication** — proof of identity by email and password and, for users enrolled in multi-factor authentication, a second factor.
- **Authorisation (RBAC)** — decision on which areas of the application a user may enter, governed by the user's base role.
- **Authority (regulated approval rights)** — decision on which regulated actions a user may sign off, governed by Authority Profiles.
- **Authority Context (`AuthzContext`)** — the user's permission envelope returned at login: base role, Authority Profiles held, active delegations, effective scopes, and a counter (claims version) used to detect when these change.
- **Authority Profile** — a named regulated permission (for example `final_quality_approver`, `qp_release_authority`). A user holds the profile through assignment or, temporarily, through delegation.
- **Delegation** — a time-bounded transfer of an Authority Profile from one user to another. A delegation cannot exceed the delegator's own scope. A delegation always has a mandatory end date.
- **Scope (seven dimensions plus tenant-wide)** — the boundary inside which an Authority Profile applies: site, product, study, supplier, module, entity type, workflow type, with an explicit tenant-wide flag and a global super-authority flag.
- **Segregation of Duties (SoD)** — a regulated rule preventing one person from playing two conflicting roles in the same record (for example, the same user cannot author and approve the same deviation).
- **Tenant** — one customer organisation in Verixa's multi-tenant database. Each tenant is logically isolated from every other tenant.
- **Membership** — the link between a user, a tenant, and a base role.
- **Base role** — coarse access tier on the membership: `admin`, `quality_lead`, `reviewer`, `auditor`, or `viewer`.
- **Session** — a record that the user has signed in. Each session has a server-side row, a JSON Web Token in a cookie, and a refresh token in a separate cookie.
- **JSON Web Token (JWT)** — short-lived signed access token containing user identifier, tenant identifier, base role, session identifier, and claims version.
- **Refresh token** — longer-lived token used to obtain a new JWT without re-login. Stored as a hash; rotated on every use; reuse is treated as a security event.
- **Cross-Site Request Forgery (CSRF) token** — a second secret tied to the session that the front end must send in a header on every state-changing request.
- **Multi-Factor Authentication (MFA)** — second proof of identity. Verixa permits Time-based One-Time Password (TOTP) authenticator apps and one-time backup codes. Short-Message-Service (SMS) MFA is prohibited.
- **Time-based One-Time Password (TOTP)** — six-digit code from an authenticator application that changes every thirty seconds.
- **Single Sign-On (SSO)** — login through the customer's identity provider over OpenID Connect (OIDC) or Security Assertion Markup Language (SAML).
- **Claims version** — counter on each (user, tenant) row that increments on every authority change. The JWT carries the version in force when minted; on refresh the server compares it to the latest persisted value.
- **Account lockout** — temporary block on a user's login after the configured number of failed password attempts within the configured window.
- **IP allowlist** — the list of network ranges from which a tenant's users are permitted to log in.
- **Session fingerprint** — the source IP prefix and normalised user agent stored with the session to detect token replay from a different network or browser.
- **Authority Resolver** — server-side service that, given a user and tenant, returns the user's Authority Context from profiles, assignments, delegations, and scope rules. Deterministic. Contains no AI.

#### Audit, electronic signature, and data integrity

- **Audit trail** — permanent record of every change in the system: who, what, when, before, after, and why. Required by 21 CFR Part 11 §11.10(e) and EU GMP Annex 11 §9.
- **Append-only log** — a database table that allows only INSERT. UPDATE and DELETE are denied at the database role level.
- **Hash chain** — each new audit row stores a hash of the previous row plus its own contents, producing a chain that any tampered row breaks visibly.
- **Advisory lock** — database primitive that ensures only one writer at a time appends to the chain, preventing fork.
- **Integrity manifest** — short file accompanying an audit-log export that names the start hash, end hash, row count, and verification status.
- **Electronic signature** — regulated signature made by re-typing the password, stating the meaning of the signature, and giving a reason for the change. The signature is linked to the signed record.
- **Controlled Approval Modal** — the standard pop-up that captures every regulated approval, identical across modules.
- **ALCOA+** — nine data-integrity principles: Attributable, Legible, Contemporaneous, Original, Accurate, Complete, Consistent, Enduring, Available.
- **GAMP 5 Category 5** — categorisation for custom-developed software subject to GxP. Implies full validation rigour.
- **Computer Software Assurance (CSA) / Computer System Validation (CSV)** — risk-based and traditional validation frameworks. Both produce IQ / OQ / PQ evidence.
- **Installation / Operational / Performance Qualification (IQ / OQ / PQ)** — validation phases proving correct installation, operation, and performance.
- **Document Quality Gateway** — the gateway through which every regulated document write must pass.
- **Human-in-the-Loop (HITL)** — pattern in which a human approves AI outputs before they take effect.
- **Three-layer guard hierarchy** — front-end pattern of `<RoleGuard>` then `<PermissionGuard>` then `<AuthorityGuard>`.
- **Mode A / B / C** — three policies for handling a stale claims version: Mode A revokes the session at next refresh (default for regulated authority changes); Mode B tags the request as stale but lets non-regulated reads continue; Mode C rejects regulated routes with `401 CLAIMS_VERSION_MISMATCH`.

#### Engineering and platform

- **Tenant Data Access Layer (TDAL)** — the only sanctioned database access wrapper; binds the tenant context so Row-Level Security applies.
- **Row-Level Security (RLS)** — database feature that restricts which rows of a table a connection can see, based on a SQL policy expression.
- **Key Management Service (KMS)** — cloud-managed key store that holds the master keys used to encrypt secrets.
- **HttpOnly cookie** — a cookie that JavaScript on the page cannot read.
- **Secure cookie** — a cookie sent only over HTTPS.
- **SameSite=Lax** — cookie attribute that prevents the browser from sending the cookie on most cross-site requests.
- **Static analysis gate** — automated check on every pull request enforcing rules at scale.

#### Regulatory and process

- **21 CFR Part 11** — United States Food and Drug Administration regulation for electronic records and electronic signatures.
- **EU GMP Annex 11** — European Union Good Manufacturing Practice annex for computerised systems.
- **EU GMP Chapter 4** — European Good Manufacturing Practice chapter for documentation and record integrity.
- **MHRA Data Integrity Guidance (2018)** — United Kingdom Medicines and Healthcare products Regulatory Agency data-integrity guidance, codifying ALCOA+.
- **CDSCO** — Central Drugs Standard Control Organisation, India's national drug regulator.

---

## 1. Module Purpose

Module 1 is the identity, session, authentication, and access-control substrate for Verixa. It establishes who a user is, that the user is the same user across requests, what coarse access the user has, and, through the Authority Resolver, which regulated decisions the user is eligible to perform. It also produces the audit-trail attribution that every other module consumes when it writes a regulated record.

The module creates regulated records (sessions, signatures, multi-factor enrolments, password history, authority assignments, the authority change log) and supports regulated workflows (login, multi-factor authentication, single sign-on, password change and reset, authority assignment and delegation). It does not by itself approve or release any clinical, manufacturing, or quality artefact; every approval downstream is gated by the Authority Context produced here.

The architectural boundary is explicit and remains explicit. Authentication answers "who are you?". Role-Based Access Control (URS-02) answers "can you enter this module?". Authority (URS-05) answers "can you approve, release, or sign off?". Authentication does not become the approval engine; it returns an Authority Context that downstream modules consume.

**Phase 1 launch note.** Phase 1 design-partner launch uses **Verixa-managed users**. OpenID Connect and Security Assertion Markup Language single sign-on remain specified in this document and are implementable, but customer single-sign-on activation is conversion-stage or customer-specific implementation scope and is not required for the first design-partner evidence workflow unless a signed design-partner agreement requires it. This launch posture is the program-plan mitigation for identity / single-sign-on delay risk and is consistent with §18.1 DEC-01-08 disposition.

---

## 2. Scope

### 2.1 In scope

- Email and password login, including pre-authentication identification, password verification, multi-factor authentication initiation, account-lockout enforcement, and IP-allowlist enforcement.
- Multi-factor authentication: Time-based One-Time Password (authenticator app) and backup codes only.
- Single sign-on per tenant: OpenID Connect and Security Assertion Markup Language; tenant administration of single sign-on configurations; persistent state tokens; callback that mints session, refresh token, and authority context.
- Session lifecycle: creation, idle and absolute timeout, refresh with claims-version compare, fingerprint check, revocation by user, revocation by administrator, revocation triggered by authority change, hijack detection, refresh-token rotation, refresh-token reuse detection.
- Password lifecycle: policy enforcement at every boundary (login, change, reset, invitation acceptance), password history, expiry warning, force-password-change flag, forgot-password email send.
- Account-lockout policy, IP-allowlist policy, session policy, password policy administration.
- Authority Resolver service, Authority Profile catalogue (with tenant-extensible custom profiles), Authority Assignment lifecycle, Authority Delegation lifecycle, Authority Scope Rules, Segregation-of-Duties rules.
- Hash-chained, append-only authority change log and authentication audit log, with database advisory-lock serialisation.
- Front-end authentication store, atomic auth-state setter, three-layer guard hierarchy, session-timeout warning, multi-factor challenge user interface, multi-factor enrolment user interface, session management user interface, security-policy administration user interface.
- Cross-Site Request Forgery protection, Cross-Site Request Forgery token regeneration on bootstrap, atomic delivery of user, Cross-Site Request Forgery token, and Authority Context on login, multi-factor completion, refresh, and bootstrap.
- Twelve-event authority audit vocabulary writers and the eighteen-event authentication audit vocabulary writers.
- Six error codes for authority and authentication failure modes.
- Inter-module wiring of Authority Context to URS-02 (Role-Based Access Control), URS-03 (Context Gate), URS-04 (Workflow / HITL / E-Signature), URS-05 (Authority Profile and Delegation), URS-06 (Audit Trail & Data Integrity), URS-08 (Tenant Management), URS-30 (Notifications), URS-31 (Document Quality Gateway), URS-32 (MIRA AI), and URS-35 (Infrastructure, Backup, Restore).

### 2.2 Out of scope

- Hardware-token multi-factor authentication (FIDO2 / WebAuthn).
- Adaptive or risk-based authentication (device-trust scoring, anomaly-based step-up).
- Passwordless e-mail magic-link login.
- Cross-tenant identity federation in a single browser session.
- Approval-workflow business logic and state machines (these are owned by URS-04 and the respective domain modules).
- Document approval business semantics (owned by URS-12 and URS-31).
- Approval-decision logic for clinical, manufacturing, or quality records.

### 2.3 Closed launch decisions

| Identifier | Closed launch decision |
|---|---|
| DEC-01-01 | The default authority-triggered session-invalidation policy is Mode A (force revoke at next refresh) for any regulated authority revocation and for any base-role downgrade. Modes B and C are not enabled by default. |
| DEC-01-02 | Access cookie and refresh cookie are scoped HttpOnly and Secure (in production), with `SameSite=Lax`, with a maximum-age of twenty-eight thousand eight hundred seconds for the access cookie, and with the refresh cookie limited to the refresh endpoint path. |
| DEC-01-03 | The front-end idle-timer carries no hard-coded fallback; the timer does not run until the server returns the active session policy. |
| DEC-01-04 | E-mail transport for password reset and authority-change notifications meets a deliverability service-level agreement of 99.5 percent over a thirty-day window. |
| DEC-01-05 | The session fingerprint tolerance permits an IPv4 /24 prefix and an IPv6 /64 prefix; tighter binding is not required. |
| DEC-01-06 | A tenant-selection branch is offered at login only when the authenticated identity has memberships in more than one active tenant. |
| DEC-01-07 | Account-lockout default thresholds are five failed attempts within fifteen minutes triggering a fifteen-minute lockout; thresholds are tenant-configurable. |
| DEC-01-08 | All error responses follow a single envelope: human message, machine-readable code in upper-snake-case, optional structured details, and a correlation identifier. |
| DEC-01-09 | Multi-factor secret material at rest is encrypted using a key managed by the cloud Key Management Service. |
| DEC-01-10 | External identity types (inspector, external auditor, supplier portal user, contract research organisation portal user, customer portal user) are modelled as base-role memberships (`viewer` for read-only, `auditor` for read-only audit access) plus an `external_type` discriminator on the membership row; external identities never hold an Authority Profile. The discriminator schema, lifecycle, and revocation rules are detailed in URS-02 and the relevant portal-feature module. |
| DEC-01-11 | The system identity `system@verixa.internal` is registered as a real user row referenced by automated jobs; additional system identities (for example for backup runs, integrations, integrity verification, and the MIRA agent) follow the same naming convention. The full list of system identities is detailed in URS-35 and URS-32 respectively and is treated as a Class 1 change-governed list. |
| DEC-01-12 | The launch seed of Authority Profiles includes those listed in §3.2.3 below; additional jurisdictional or tenant-defined Authority Profiles are managed through the Authority Profile lifecycle in §3.2.4. |

---

## 3. User Roles and Permissions

### 3.1 Architecture

The Verixa role universe has three layers, plus two non-employee identity categories. Readers new to the architecture may benefit from reading the worked examples in §3.7 first — they show how the layers combine in concrete scenarios (deviation closure, document approval, batch release).

- **Layer 1 — Base role.** Coarse access tier set on the user-tenant membership.
- **Layer 2 — Authority Profile.** Named regulated approval right; assigned per user; gates every regulated approve, release, dispose, sign-off, closure, certification action across every module.
- **Layer 3 — Delegation.** Time-bounded transfer of an Authority Profile from one user to another; sits between users; cannot exceed the delegator's scope; carries a mandatory end date.

External identity categories:

- **External identities** — non-employee users (inspectors, external auditors, supplier-portal users, contract-research-organisation portal users, customer-portal users). External identities map onto the existing base-role hierarchy, typically `viewer`, optionally `auditor` for read-only audit access, with an `external_type` discriminator on the membership row. External identities NEVER hold an Authority Profile.
- **System and service identities** — non-human accounts used by background jobs, integrations, the integrity verification job, and the MIRA AI agent. System identities NEVER hold an Authority Profile and NEVER electronically sign a regulated record.

### 3.2 Layer 1 — Base roles

#### 3.2.1 Tenant-level base roles

The five base roles are fixed and enforced at the database level. The role list is not extensible.

| Base role | Mutability | Purpose |
|---|---|---|
| `admin` | Immutable rights — the permission matrix MUST NOT weaken `admin`. | Tenant-level configuration of users, master data, basic policies. |
| `quality_lead` | Mutable in the permission matrix. | Quality-team member who edits, submits, and (with the matching Authority Profile) approves regulated records. |
| `reviewer` | Mutable. | Comment, review, acknowledge; cannot approve. |
| `auditor` | Mutable. | Read-only access including audit-trail reads. |
| `viewer` | Mutable. | Read-only access to records the user is in scope for. |

Base role is necessary for module access. Base role alone is NEVER sufficient for a regulated decision; every regulated decision additionally requires the matching Authority Profile in §3.3.

#### 3.2.2 Platform-level identities

Two cross-tenant platform identities exist for Verixa support and incident response. They are granted through a separate platform identity store, not through tenant memberships.

| Identity | Scope | Purpose |
|---|---|---|
| `platform_admin` | Cross-tenant | Verixa platform staff with cross-tenant visibility for support and incident response. |
| `super_admin` | Cross-tenant | Verixa platform staff with full administrative authority over the platform. |

#### 3.2.3 External identities — mapping onto base roles

External identities are non-employee users. They are NOT a separate role tier. Each external identity is a membership row with one of the base roles in §3.2.1 plus an `external_type` discriminator that names the external relationship.

| Discriminator | Base role mapping | Example access |
|---|---|---|
| `inspector` | `auditor` (read-only audit access) | Time-bounded view of an inspection pack; exports the inspection-pack PDF. |
| `external_auditor` | `auditor` | Read-only access scoped to the audit engagement; watermarked exports. |
| `supplier_user` | `viewer` | Limited supplier-portal scope: their own qualification and documents; cannot read other suppliers; cannot read tenant-internal records. |
| `cro_user` | `viewer` | Limited contract-research-organisation portal scope to a specific study identifier. |
| `customer_user` | `viewer` | Limited customer-portal scope: own complaints, own status. |

External identities carry no Authority Profile and NEVER appear as the actor on a regulated mutation. Their lifetimes are bounded to the engagement (inspection window, audit engagement, contract period). External identities authenticate through the same login surface as employees.

#### 3.2.4 System and service identities

System and service identities are non-human accounts. They are always named, never the literal string `'system'`. They never electronically sign and never carry an Authority Profile. They are used only by jobs explicitly chartered to act outside an HTTP request lifecycle.

The launch list is summarised below. The full registry of system identities is maintained in URS-35.

| Identity | Purpose |
|---|---|
| `system@verixa.internal` | Auto-expiry job, scheduled reminders, cron-driven cleanup. |
| `backup-runner@verixa.internal` | Scheduled and on-demand backup runs. |
| Additional system identities | Maintained per URS-35; addition of any identity is a Class 1 change. |

### 3.3 Layer 2 — Authority Profiles

#### 3.3.1 Two-tier catalogue

The Authority Profile catalogue is two-tier and tenant-extensible.

- **Tier 1 — Global Authority Profiles.** Seeded by Verixa platform; flagged as system profiles; immutable once referenced. Apply across all tenants.
- **Tier 2 — Tenant-defined Authority Profiles.** Created by a holder of `tenant_admin_authority` to encode the tenant's own business process. Same scope-rule, segregation-of-duties, delegation, electronic-signature, and audit-chain machinery as Tier 1. A tenant-defined profile may share a key with a global profile to override it for that tenant.

Both tiers carry the same metadata: identifier, tenant identifier (null for global), key, label, description, regulated flag, approval level, requires-electronic-signature flag, requires-dual-sign flag, allows-override flag, allows-delegation flag, effective-from, effective-to, system flag.

#### 3.3.2 Scope dimensions

Every Authority Profile assignment is constrained by scope rules across seven dimensions plus tenant-wide and a global super-authority flag:

- site, product, study, supplier, module, entity type, workflow type, plus tenant-wide and global super-authority.

Tenant-defined Authority Profiles use the same scope-rule registry as global profiles.

#### 3.3.3 Launch seed of Tier 1 Authority Profiles

The launch global seed includes the following keys. Additional keys are added through URS-13 with founder electronic signature.

`final_quality_approver`, `qp_release_authority`, `qa_approver`, `hitl_final_reviewer`, `supplier_quality_manager`, `supplier_quality_approver`, `supplier_coa_reviewer`, `supplier_agreement_manager`, `stability_reviewer`, `protocol_approval_authority`, `shelf_life_approval_authority`, `final_release_authority`, `final_approver`, `deficiency_acceptance_authority`, `deficiency_closure_authority`, `checklist_release_authority`, `question_bank_authority`, `lesson_publish_authority`, `triple_sig_reviewer`, `triple_sig_approver`, `recall_approver`, `quarantine_approver`, `report_approval_authority`, `risk_final_approver`, `risk_approver`, `mbr_approval_authority`, `extraction_approver`, `em_result_approver`, `em_limit_approver`, `document_reviewer`, `document_approver`, `restore_approver`, `operations_manager`, `qa_lead`, `tenant_admin_authority`, `global_quality_oversight`, `approval_authority`.

#### Jurisdictional batch-release Authority Profiles

The release decision for a manufactured batch is jurisdiction-specific. Each registered market enforces a distinct legal construct for who may sign release. The launch seed includes one Authority Profile per recognised jurisdiction; the runtime resolver selects the required profile (or set of profiles) by the product's registration jurisdiction. The pattern is deliberate: rather than seeding combinatorial dual or triple keys (`dual_us_eu`, `dual_us_eu_in`, and so on, which would explode beyond manageability), multi-jurisdiction products are handled in URS-04 by composing a workflow node with `approval_mode = parallel` and the multiple jurisdictional keys in `requiredAuthorityKeys[]`. The legacy combinatorial key `dual_ap_india_qp_eu` is retained for backward compatibility with existing dual-registration products but is not the recommended pattern for new jurisdictions.

| Key | Jurisdiction | Regulatory construct | Anchor |
|---|---|---|---|
| `ap_india` | India | "Authorised Person" listed on the manufacturing licence; personally accountable to the Central Drugs Standard Control Organisation. | Drugs and Cosmetics Act 1940; Drugs and Cosmetics Rules 1945, Schedule M |
| `qp_eu` | European Union | "Qualified Person" — a named, regulator-registered individual personally certifying batch release for the European Union market. | Directive 2001/83/EC Article 51; eligibility under Article 49; EU GMP Annex 16 |
| `qp_uk` | United Kingdom | "Qualified Person" under United Kingdom GMP; post-Brexit retains the QP construct distinct from the European Union register. | Human Medicines Regulations 2012 (SI 2012/1916); MHRA Orange Guide; UK GMP Annex 16 |
| `qa_release_us` | United States | "Qualified individual in the Quality Control Unit" — release decision is the responsibility of the QA unit, not a single regulator-registered individual; a designated qualified individual signs on behalf of the unit. | 21 CFR 211.22 (Responsibilities of the Quality Control Unit); 21 CFR 211.165 (Testing and release for distribution); 21 CFR 211.194 (Laboratory records) |
| `qa_release_ca` | Canada | "Person in charge of the quality control department" with the required qualifications, education, and experience; designated responsible person signs the lot release. | Health Canada Good Manufacturing Practices Guide (GUI-0001); Food and Drug Regulations, Division 2 (Sections C.02.013–C.02.015) |
| `dual_ap_india_qp_eu` | Dual jurisdiction (India + European Union) | Legacy combinatorial key; retained for products registered before the introduction of the parallel-workflow pattern. | Inherits from `ap_india` and `qp_eu`; both signatures required when held as a single key |

For products registered in jurisdictions not listed above (for example Brazil ANVISA `Responsável Técnico`; Japan PMDA Marketing Authorisation Holder responsible person; China NMPA Quality Authorised Person; Australia TGA released-for-supply person; Switzerland Swissmedic responsible person; Saudi SFDA QP), the Authority Profile is created by the tenant administrator as a Tier 2 custom profile per §3.3.4 until the global launch seed is extended through URS-13 with founder electronic signature. Each such tenant-defined jurisdictional profile uses the same Authority Resolver, scope rules, segregation-of-duties engine, electronic signature, hash-chained audit, and delegation engine as the seeded jurisdictions.

Multi-jurisdiction products (a single batch released to two or more markets simultaneously) MUST be modelled in URS-04 by configuring the batch-release workflow node with `approval_mode = parallel` and the relevant jurisdictional Authority Profile keys in `requiredAuthorityKeys[]`. Each required signature is captured by a separate human (segregation of duties is enforced per signature), recorded in `electronic_signatures`, linked into `authority_change_log`, and reflected in the batch-release audit trail. The runtime resolver routes by the product's `registration_jurisdiction` field; for products registered in `n` jurisdictions, `n` distinct human signatures are required at release.

#### 3.3.4 Lifecycle and rules

- **Key uniqueness.** `(tenant_id, key)` is unique. A tenant-defined profile with the same key as a global profile overrides it for that tenant.
- **Key immutability post-reference.** Once a profile has been referenced by an active assignment, delegation, scope rule, or workflow node, its key MUST be immutable.
- **System flag.** Global profiles MUST carry the system flag set; the system-profile guard MUST prevent deactivation or relabelling of system profiles.
- **CRUD audit.** Every create, update, deactivate, assign, delegate, and revoke MUST emit an event into the authority change log with a hash chain and into the consolidated audit log.
- **Tenant-scoped administration.** Tenant administrators may create or deactivate Tier 2 profiles for their own tenant only. Cross-tenant authority CRUD is blocked by Row-Level Security and by the Tenant Data Access Layer.
- **Class assignment for URS-13.** Adding a Tier 2 profile is operational tenant configuration (Class 3 change). Deprecating an in-use profile is a Class 1 change requiring revocation cascade.

### 3.4 Layer 3 — Delegations

Delegations transfer an Authority Profile from one user to another for a bounded period. Rules:

- The delegator MUST hold the Authority Profile in active state at the moment of delegation creation.
- The delegation MUST NOT exceed the delegator's own active scope (no privilege escalation).
- The delegation MUST carry a non-null `effective_to` strictly greater than `effective_from`.
- Auto-expiry runs no less frequently than hourly; expired delegations transition to expired status, increment claims version of both users, and emit the expiry event into the authority change log under the system identity.
- Delegations to inactive members are rejected.

### 3.5 Workflow-step approval roles

Workflow templates carry per-node approval requirements: required Authority Profile keys, minimum approver count, segregation-of-duties requirement, approval mode (single, dual, sequential, parallel), final-approver-required flag, secondary Authority Profile, override Authority Profile, electronic-signature requirement, segregation rule reference, source state, target state, entity type, and workflow family. Tenants compose custom approval chains by referencing global or tenant-defined Authority Profile keys at each node.

### 3.6 Subject Matter Expert (SME) roles

Subject Matter Experts are not a separate Authority Profile. They are a content-authorship pattern keyed by `(tenant, base role, regulatory body)`. SME content (for example inspection question banks) flows through draft → under review → active → superseded → archived, governed by the `question_bank_authority` Authority Profile, attributed to a real user, and contributes to inspection readiness scoring (URS-22). Tenants extend the Subject Matter Expert taxonomy by adding additional `(role, regulatory body)` entries that match their own regulatory exposure.

### 3.7 Worked examples — applying the role architecture inside Module 1

This section explains, in plain language, how the three-layer role architecture (§3.1–§3.5) works in practice for the records and decisions Module 1 owns: identity, sessions, authority assignments, delegations, multi-factor enrolments, and security policies. Domain-module worked examples (deviation closure, document approval, batch release, and so on) appear in their respective module URS documents (URS-16, URS-12, URS-23, …); Module 1 supplies the substrate they consume.

#### Mental model

Two concepts are deliberately separate and must not be conflated.

- **Owner, author, assignee, target user** are *record-level fields* (for example `deviation.owner_id`, `sop.author_id`, `user_authority_assignments.user_id`). They name the human who is *accountable* for the record. They are not roles. They are not Authority Profiles. The system uses them for routing, notifications, queues, and Segregation-of-Duties checks.
- **Authority Profile** (Layer 2) is a *regulated permission* that gates a regulated decision (assign, revoke, delegate, sign off, release, close). It is checked at the moment of the decision through the Authority Resolver and `<AuthorityGuard>`. A user holds an Authority Profile through direct assignment or, temporarily, through delegation.

Combining them: to *act* on a record (read, edit, submit) the user needs **Layer 1 base role + permission**. To *be accountable* for a record the user is named in the **record-level field**. To *make a regulated decision* on the record the user must additionally hold the **Layer 2 Authority Profile** in scope. To *close the loop* the system enforces **Segregation of Duties** — the same person cannot play two conflicting parts on the same record.

#### Worked example A — A new employee signs in via Single Sign-On for the first time

A new employee at a customer site signs in to Verixa via the customer's identity provider for the first time. Module 1 must establish identity and a session without ever auto-granting any regulated approval right.

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | Segregation of Duties |
|---|---|---|---|---|
| Just-in-time provisioned user (the new employee) | `users.id`, `memberships.user_id` | `viewer` (always — Single Sign-On never provisions higher) | none — Single Sign-On never auto-assigns an Authority Profile | — |
| Identity-provider integration | identity-provider configuration row | not applicable (system path) | not applicable | — |
| Authority assigner (later) | not yet — see worked example B | `admin` or `tenant_admin` (when assignment occurs) | `tenant_admin_authority` (when assignment occurs) | the assigner MUST NOT later self-revoke (per the self-modification block in §6.5 BR-01) |

**Narrative.** Sarah joins Acme Pharma and the customer's identity provider passes her identity to Verixa for the first time. The single-sign-on callback path validates the assertion and just-in-time creates one row in `users` and one row in `memberships` with `role = 'viewer'`. Authority Resolver returns an Authority Context with an empty `authorityProfiles` array. Sarah's user interface renders read-only across the platform; every regulated approve, release, sign-off, and closure button is disabled and shows the tooltip "Requires [profile] authority." The audit log carries `LOGIN_SUCCESS` and `AUTHZ_CONTEXT_RESOLVED` for the session creation and zero Authority Profile assignments. Sarah cannot make a regulated decision until an authorised administrator explicitly assigns her one (worked example B).

#### Worked example B — Tenant administrator assigns an Authority Profile to a user

Sarah's manager has approved her promotion to Quality Approver for the Chennai antibiotic line. The tenant administrator must grant her the `final_quality_approver` Authority Profile within the right scope.

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | Segregation of Duties |
|---|---|---|---|---|
| Assigning administrator (the actor) | `user_authority_assignments.created_by` | `admin` or `tenant_admin` | `tenant_admin_authority` | the administrator MUST NOT assign an Authority Profile to themselves at a higher tier than they currently hold (no privilege escalation) |
| Target user (the recipient) | `user_authority_assignments.user_id` | the target's existing `memberships.role` (typically `quality_lead`) | the assignment is the act of granting; the user does not need any prior Authority Profile | — |
| Scope (where the authority applies) | `user_authority_assignments.scope_restriction` | not applicable | not applicable; scope is constrained by the active scope rules registered for the Authority Profile | — |
| Segregation-of-Duties evaluation (system) | runtime check at insertion | not applicable | not applicable | the new assignment MUST NOT violate any active Segregation-of-Duties rule for the target's existing assignments |

**Narrative.** The QA Manager (a `tenant_admin` holding `tenant_admin_authority`) opens the authority assignments page and selects Sarah from the user list. The QA Manager picks `final_quality_approver` from the Tier 1 catalogue, scopes the assignment to `site = Chennai` and `product = antibiotic-line`, sets effective from today with no end date, and clicks "Assign." The Controlled Approval Modal collects re-authentication, meaning of signature ("I assign the `final_quality_approver` authority to sarah@acmepharma.com within Chennai/antibiotic-line, effective today"), and reason for change ("QA Approver promotion approved per HR-2026-0815"). The system validates against active Segregation-of-Duties rules, writes the assignment row, atomically increments Sarah's claims version, and emits `AUTHORITY_ASSIGNED` and `CLAIMS_VERSION_INCREMENTED` into the hash-chained authority change log linked to the new electronic signature. Sarah's next session refresh receives the updated Authority Context; her approve buttons enable, in scope. The QA Manager could not have assigned an authority to themselves at a higher tier; the self-modification guard would have rejected it.

#### Worked example C — A Quality Approver delegates an Authority Profile during leave

Sarah is going on annual leave. She must hand her `final_quality_approver` rights to a peer in scope, time-bounded, without weakening the audit trail.

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | Segregation of Duties |
|---|---|---|---|---|
| Delegator (Sarah) | `approval_delegations.from_user_id` | `quality_lead` | MUST currently hold the Authority Profile being delegated, in active state, in the scope being delegated | the delegator cannot delegate to themselves; the delegated scope cannot exceed the delegator's own active scope |
| Delegate (peer) | `approval_delegations.to_user_id` | typically `quality_lead` | none required at the moment of delegation; the delegation itself confers the right | the delegate MUST be an active member of the same tenant |
| Effective period | `effective_from`, `effective_to` (mandatory non-null) | not applicable | not applicable | `effective_to` strictly greater than `effective_from`; cannot exceed the delegator's own assignment `effective_to` |
| Auto-expiry actor | `system@verixa.internal` | system identity | not applicable | — |

**Narrative.** Sarah opens her delegations page on 25 July, picks `final_quality_approver`, names Raj as the delegate, sets the scope to Chennai/antibiotic-line (matching her own scope; she could not have widened it), sets effective from 1 August to 14 August, gives the reason "Annual leave 1–14 August 2026," and electronically signs the delegation through the Controlled Approval Modal. The system writes the delegation, atomically increments both Sarah's and Raj's claims versions, and emits `DELEGATION_CREATED` and `CLAIMS_VERSION_INCREMENTED` (twice — one per user). Raj's session refresh on 1 August receives the delegation in his Authority Context; his approve buttons enable inside the Chennai/antibiotic-line scope only. At 00:00 on 15 August the auto-expiry job runs under the named system identity `system@verixa.internal`, transitions the delegation to `expired`, increments both users' claims versions, and emits `DELEGATION_EXPIRED`. Raj's next refresh removes the right; both users receive notification e-mails.

#### Worked example D — Tenant administrator revokes a regulated Authority Profile and the cascade fires

Sarah is reassigned to a different role; her `final_quality_approver` authority is no longer appropriate. The tenant administrator must revoke the right and ensure that any open sessions are kicked out without waiting for token expiry.

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | Segregation of Duties |
|---|---|---|---|---|
| Revoking administrator | `user_authority_assignments.revoked_by` | `admin` or `tenant_admin` | `tenant_admin_authority` | reason for change is mandatory; electronic signature is mandatory |
| Target user (Sarah) | `user_authority_assignments.user_id` | unchanged base role | the revoked Authority Profile | — |
| System cascade actor | `user_sessions.revoked_by` (system attribution) | system | not applicable | — |

**Narrative.** The QA Manager opens Sarah's authority detail page, clicks "Revoke," and the modal warns "This will revoke regulated approval rights and revoke all 2 active sessions of sarah@acmepharma.com. Confirm reason." The QA Manager re-authenticates and signs with reason "Role reassignment effective 2026-08-20 per HR-2026-0820." In a single database transaction the system updates the assignment status to revoked, writes `AUTHORITY_REVOKED` (with the regulated flag set) into the authority change log, atomically increments Sarah's claims version, revokes both her active sessions (laptop and phone), and emits `SESSION_REVOKED_AUTHORITY_CHANGE` per session linked to the revocation electronic signature. On Sarah's laptop, the next refresh — which can occur within seconds — returns `401 SESSION_REVOKED_AUTHORITY_CHANGE`; the user interface clears auth and redirects her to the login page with the explanatory message "Your session was terminated because your authority was updated. Please log in again." Sarah may still log in (her account is active) but her approve buttons are disabled because her Authority Context no longer carries `final_quality_approver`.

#### Worked example E — Tenant administrator creates a Tier 2 custom Authority Profile to encode a client-specific business process

Acme Pharma's quality system distinguishes between "Plant Quality Head" and "Site Quality Head" for parallel batch approvals. The global catalogue does not carry these specialisations. The tenant administrator must encode them.

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | Notes |
|---|---|---|---|---|
| Tenant administrator (the author of the new profile) | `authority_profiles.created_by` | `tenant_admin` | `tenant_admin_authority` | the new profile is scoped to the tenant (`tenant_id` is non-null; `is_system = false`) |
| Authority Profile catalogue | `authority_profiles.id`, `key`, `label`, `regulated`, `requires_esign`, `allows_delegation` | not applicable | not applicable | every Tier 2 profile inherits the same Authority Resolver, scope rules, Segregation of Duties, electronic-signature, audit-chain, delegation, and notification machinery as Tier 1 |
| Workflow composition (downstream of Module 1) | `workflow_node_approval_requirements.required_authority_keys[]` | URS-04 owns | not applicable | the new profile is referenced from URS-04 workflow templates by key |

**Narrative.** Acme Pharma's tenant administrator opens the Authority Profile catalogue page, creates `plant_quality_head_acme` (regulated, requires electronic signature, allows delegation, tenant-wide scope) and `site_quality_head_acme` (regulated, requires electronic signature, allows delegation, scope dimension `site`), and electronically signs the catalogue creations with reason "Acme batch-release process requires parallel plant + site approvals per Acme SOP-QA-002." The two new profile rows are persisted with the tenant identifier set and `is_system = false`. The tenant's batch-release workflow template in URS-04 is then configured to require both Authority Profiles in `parallel` mode at the batch-release transition. From this point on every batch-release decision in Acme's tenant requires two independent electronic signatures by two distinct humans holding the two distinct profiles. The Authority Resolver, segregation-of-duties engine, delegation engine, hash-chained audit, and notifications all apply identically to these tenant-defined profiles as to the global ones. No platform code changed; no global catalogue changed; the client's business process is encoded.

#### Worked example F — Authority Resolver outage degrades safely

A momentary database failure causes the Authority Resolver to stop returning Authority Contexts. Module 1 must distinguish "you have no authority" from "we cannot tell what your authority is right now."

| Lifecycle role | Record-level field | Layer 1 base role | Layer 2 Authority Profile | System effect |
|---|---|---|---|---|
| Every authenticated user | unchanged | unchanged | unchanged | sessions remain active for read-only paths |
| Bootstrap response | the response carries `authzContextStatus = 'unavailable'` and a correlation identifier | not applicable | not applicable | HTTP `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` |
| Front end | persistent banner appears tenant-wide | not applicable | not applicable | every `<AuthorityGuard>` button is disabled with the same tooltip |
| Security Operations Centre | alert fired with the correlation identifier | system | not applicable | continuous until resolved |
| Auto-recovery | next bootstrap call after resolver returns to health | not applicable | not applicable | banner clears; approve buttons re-enable |

**Narrative.** At 14:32 on a Tuesday the Authority Resolver cannot read the database for two minutes. Every authenticated request to the bootstrap endpoint returns `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` with an explicit correlation identifier and `authzContextStatus = 'unavailable'`. The user interface renders the persistent banner "Authority context unavailable — approval actions temporarily disabled." Every regulated button across every module is disabled. The Security Operations Centre receives a critical alert; the on-call engineer investigates and brings the resolver back to health at 14:34. The next bootstrap poll on each user's screen returns a successful Authority Context; the banner clears; approve buttons re-enable. Throughout the outage no user was logged out; read-only views continued to function; no regulated decision could have been made (back end would also have refused with `403 AUTHORITY_CHECK_FAILED`). The audit log carries one `authz_context_resolution_failed` event per affected request, all sharing the correlation identifier — an inspector can reconstruct the full incident from a single chain.

#### Reading these examples in context

The examples above stay inside Module 1's surface: identity, sessions, authority assignments, delegations, and resolver behaviour. The same architectural pattern (record-level accountability fields plus Authority Profile gating plus Segregation-of-Duties enforcement plus electronic signature plus hash-chained audit) is reused by every other module. Worked examples for deviation closure, Standard Operating Procedure authoring, Document Quality Gateway intake, Corrective and Preventive Action closure, batch release, environmental excursion review, complaint handling, regulatory submission release, and so on appear in URS-16, URS-12, URS-31, URS-18, URS-23, URS-25, URS-14, URS-27, and the relevant module URS documents. Module 1 supplies the substrate (Authority Resolver, Authority Profile catalogue, claims version, change log, Controlled Approval Modal contract). URS-04 owns the workflow templates and the Controlled Approval Modal user interface. URS-05 owns the Authority Profile lifecycle and Segregation-of-Duties rule registry. URS-06 owns the universal audit substrate.

### 3.8 Module 1 administrative role-permission matrix

The matrix below covers Module 1's own administrative surface (login, sessions, multi-factor authentication, single sign-on, authority management, audit-log export). Every regulated row is gated by base role plus the matching Authority Profile. Other modules carry their own matrices.

| Action (within Module 1) | viewer | reviewer | quality_lead | auditor | admin | platform_admin | super_admin | system identity | Authority Profile when applicable |
|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|---|
| Log in (own account) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Log out (own session) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| List own sessions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Revoke own session(s) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Change own password | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Forgot / reset own password | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Accept invitation | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Enrol multi-factor authentication (own) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Remove multi-factor enrolment (own) | ✓ + sign | ✓ + sign | ✓ + sign | ✓ + sign | ✓ + sign | ✓ + sign | ✓ + sign | — | — |
| List sessions of another user | — | — | — | — | ✓ | support / break-glass only | support / break-glass only | — | — |
| Revoke session of another user | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | — |
| Read security policies | ✓ | ✓ | ✓ | ✓ | ✓ | support / break-glass only | support / break-glass only | — | — |
| Edit security policies | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Read single sign-on configurations | — | — | — | — | ✓ | support / break-glass only | support / break-glass only | — | — |
| Create / update / delete single sign-on configurations | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Read Authority Profile catalogue (own tenant) | — | — | — | — | ✓ | support / break-glass only | support / break-glass only | — | — |
| Create / update / deactivate Tier 2 Authority Profile (tenant-defined) | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Create / update / deactivate Tier 1 Authority Profile (global) | — | — | — | — | — | ✓ + sign | ✓ + sign | — | platform-owned; executive authority sign-off |
| Assign Authority Profile to user | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Revoke Authority Profile assignment | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Create delegation (own profile to another user) | — | — | ✓ + sign | — | ✓ + sign | support / break-glass only | support / break-glass only | — | the same Authority Profile being delegated |
| Revoke own delegation | — | — | ✓ + sign | — | ✓ + sign | support / break-glass only | support / break-glass only | — | — |
| Revoke another user's delegation | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Read authority change log | — | — | — | ✓ | ✓ | support / break-glass only | support / break-glass only | — | — |
| Export authority change log | — | — | — | — | ✓ + sign | support / break-glass only | support / break-glass only | — | `tenant_admin_authority` |
| Auto-expire authority assignment / delegation | — | — | — | — | — | — | — | ✓ | — |
| Use `global_quality_oversight` (break-glass) | — | — | — | — | — | ✓ + sign + alert | ✓ + sign + alert | — | `global_quality_oversight` (auto-expiry ≤ 24 hours; mandatory reason; SOC alert) |
| Read authentication audit log | — | — | — | ✓ | ✓ | ✓ | ✓ | — | — |

External identities (§3.2.3) are out of Module 1's administrative surface; they cannot perform any of the rows above except own-account login, session, and password lifecycle actions if their `external_type` permits.

---

## 4. End-to-End User Journeys

Every journey below maps to a screen, a state-machine transition, and a set of audit and electronic-signature events. Where AI is referenced, AI is suggestion-only. Sequence diagrams for the regulatorily-sensitive journeys are inline.

### J-01 — Email and password login (no multi-factor authentication, single tenant)

- Trigger: unauthenticated user navigates to the login page.
- Steps: user submits credentials; back end evaluates IP allowlist and lockout, verifies password, mints session and refresh token, resolves Authority Context, returns the login response with user, Cross-Site Request Forgery token, and Authority Context; front end stores the auth state atomically and navigates to the dashboard.
- Audit events: `LOGIN_SUCCESS`, `AUTHZ_CONTEXT_RESOLVED`.

#### Diagram J-01 — Login (no multi-factor) sequence

```mermaid
sequenceDiagram
  autonumber
  participant U as User
  participant FE as Frontend
  participant API as Auth API
  participant DB as Database
  participant AR as Authority Resolver
  participant AUD as Authentication Audit Log

  U->>FE: enter email + password, submit
  FE->>API: POST /auth/login
  API->>DB: evaluate IP allowlist + lockout
  alt blocked
    API-->>FE: 403 IP_NOT_ALLOWED / 423 ACCOUNT_LOCKED
    API->>AUD: append event
  else allowed
    API->>DB: verify password (Argon2id) + history
    alt invalid
      API->>AUD: append login_failure
      API-->>FE: 401 INVALID_CREDENTIALS
    else valid
      API->>DB: insert session + refresh token (claims_version)
      API->>AR: resolveAuthzContext(user, tenant)
      AR-->>API: Authority Context
      API->>AUD: append login_success + authz_context_resolved
      API-->>FE: 200 LoginResponse {user, csrfToken, authzContext}
      FE->>FE: setAuthState atomic; isAuthenticated = true
    end
  end
```

### J-02 — Email and password login with multi-factor authentication

- Trigger: user enrolled in multi-factor authentication submits credentials.
- Steps: back end persists challenge with attempt counter and time-to-live; front end navigates to the multi-factor challenge page without setting authenticated state; user enters six-digit code; on success the back end mints session and refresh token and returns the full login response.
- Audit events: `MFA_CHALLENGE`, `MFA_SUCCESS` or `MFA_FAILURE`, `LOGIN_SUCCESS`, `AUTHZ_CONTEXT_RESOLVED`.

#### Diagram J-02 — Login with multi-factor sequence

```mermaid
sequenceDiagram
  autonumber
  participant U as User
  participant FE as Frontend
  participant API as Auth API
  participant DB as Database
  participant AR as Authority Resolver
  participant AUD as Authentication Audit Log

  U->>FE: submit email + password
  FE->>API: POST /auth/login
  API->>DB: validate credentials; user has active multi-factor enrolment
  API->>DB: insert challenge {token, attempts, max_attempts, ttl}
  API->>AUD: append mfa_challenge
  API-->>FE: 200 {mfaRequired, mfaChallenge, methods}
  FE-->>U: navigate to multi-factor challenge page
  U->>FE: enter six-digit code
  FE->>API: POST /auth/mfa/complete
  API->>DB: verify code; consume challenge or reject
  alt success
    API->>DB: insert session + refresh token
    API->>AR: resolveAuthzContext
    AR-->>API: Authority Context
    API->>AUD: append mfa_success + login_success + authz_context_resolved
    API-->>FE: 200 LoginResponse
  else failure
    API->>DB: increment attempts; if exhausted lock challenge
    API->>AUD: append mfa_failure or mfa_challenge_exhausted
    API-->>FE: 401 MFA_INVALID_CODE / 401 MFA_ATTEMPTS_EXCEEDED / 401 MFA_CHALLENGE_EXPIRED
  end
```

### J-03 — Login with multi-tenant selection

- Trigger: user has active memberships in more than one tenant.
- Steps: after credential and multi-factor checks the back end returns a tenant-selection response; front end renders the selection without setting authenticated state; on selection the back end mints a session scoped to that tenant.

### J-04 — Forced password change after administrator reset

- Trigger: administrator has flagged the user's force-password-change indicator.
- Steps: login returns the response with the flag set and a null Authority Context; front end navigates to the change-password page and disables every other navigation; on success all other sessions of the user are revoked and the claims version increments.

### J-05 — Forgot password and reset

- Trigger: user clicks "Forgot password".
- Steps: the back end always returns success regardless of whether the e-mail exists, to prevent enumeration; if the e-mail exists, a one-time reset token is issued with a fifteen-minute time-to-live and an e-mail is sent; the user opens the link and submits a new password; the back end validates against the policy and history, persists the new hash, revokes all sessions, and audits.

### J-06 — Invitation acceptance

- Trigger: invitation e-mail link.
- Steps: back end validates the invitation token; user submits a password against the policy; back end creates the session and writes the password history. Acceptance never auto-assigns an Authority Profile.

### J-07 — Single sign-on

- Trigger: user clicks the single-sign-on button.
- Steps: front end performs a full-page redirect; back end persists state token, redirects to the identity provider; on callback the back end validates state, exchanges code for identity token, looks up or just-in-time creates the user with the `viewer` role only (no auto-assigned Authority Profile), mints session and refresh token, resolves Authority Context, sets cookies, and redirects to the dashboard root; the front end then bootstraps via the bootstrap endpoint.

#### Diagram J-07 — Single-sign-on callback sequence

```mermaid
sequenceDiagram
  autonumber
  participant U as User
  participant FE as Frontend
  participant IDP as Identity Provider
  participant API as Auth API
  participant DB as Database
  participant AR as Authority Resolver

  U->>FE: click single-sign-on button
  FE->>U: redirect to /auth/sso/{provider}
  U->>API: GET /auth/sso/{provider}
  API->>DB: insert state token (ttl)
  API-->>U: 302 to identity provider
  U->>IDP: authenticate
  IDP-->>U: 302 back to callback URL
  U->>API: GET callback
  API->>DB: validate state; mark used
  alt state invalid
    API-->>U: 302 to login with error
  else valid
    API->>IDP: exchange code for identity token
    IDP-->>API: identity claims
    API->>DB: lookup or just-in-time create user (viewer only)
    API->>DB: insert session + refresh token
    API->>AR: resolveAuthzContext
    AR-->>API: Authority Context
    API-->>U: 302 to dashboard root
    U->>FE: GET /
    FE->>API: GET /auth/me
    API-->>FE: LoginResponse with regenerated Cross-Site Request Forgery token + Authority Context
    FE->>FE: setAuthState atomic
  end
```

### J-08 — Multi-factor enrolment

- Trigger: user navigates to the multi-factor settings page.
- Steps: back end issues a pending enrolment with secret and quick-response code; user scans, enters first six-digit code; back end activates the enrolment and displays one-time backup codes.

### J-09 — Session list and revocation

- Trigger: user navigates to the sessions page.
- Steps: list lists each active session by source IP, parsed device, created-at, last-active-at, expires-at, with the current device flagged; user revokes a non-current session.

### J-10 — Idle session timeout with warning and back-end revoke

- Trigger: user inactive for the policy idle limit minus two minutes.
- Steps: front end shows a warning banner with countdown and "Stay signed in" or "Sign out"; on time-out or sign-out the back end revokes the session and the front end redirects.

### J-11 — Refresh token cycle with claims-version compare

- Trigger: access cookie expired but refresh cookie valid.
- Steps: front-end interceptor calls the refresh endpoint; back end validates refresh token, compares session claims version with the persisted value; on mismatch combined with a regulated authority change or a base-role downgrade the back end revokes the session and returns the dedicated 401 error code; otherwise mints a new access token, returns the updated login response, and the original request is retried.

#### Diagram J-11 — Refresh and claims-version comparison sequence

```mermaid
sequenceDiagram
  autonumber
  participant FE as Frontend
  participant API as Auth API
  participant DB as Database
  participant ACL as Authority Change Log
  participant AR as Authority Resolver

  FE->>API: any request → 401 TOKEN_EXPIRED
  FE->>API: POST /auth/refresh (refresh cookie)
  API->>DB: validate refresh token
  alt token reused
    API->>DB: revoke all sessions for user
    API->>DB: append refresh_token_reuse_detected
    API-->>FE: 401 TOKEN_REUSE_DETECTED
  else valid
    API->>DB: read session.claims_version + token.claims_version
    alt versions equal
      API->>AR: resolveAuthzContext (refresh)
      AR-->>API: Authority Context, new claims_version
      API->>DB: rotate refresh token; mint new access token
      API-->>FE: 200 LoginResponse
    else mismatch
      API->>ACL: read recent events for user
      alt regulated authority revoked OR role downgraded
        API->>DB: revoke session
        API->>DB: append session_revoked_authority_change
        API-->>FE: 401 SESSION_REVOKED_AUTHORITY_CHANGE
        FE->>FE: clear auth → redirect to login
      else non-critical change
        API->>AR: resolve fresh Authority Context
        API-->>FE: 200 LoginResponse with new claims_version
      end
    end
  end
```

### J-12 — Authority change forces re-login (cascade)

- Trigger: administrator revokes a regulated Authority Profile assignment for a target user.
- Steps: revocation is electronically signed; the back end writes the revoke event with the regulated flag, increments the target's claims version, and revokes every active session of the target; the target's next refresh returns the dedicated 401 error code.

#### Diagram J-12 — Authority revoke and session-invalidation cascade

```mermaid
sequenceDiagram
  autonumber
  participant ADM as Administrator
  participant FE as Administrator UI
  participant API as Authority API
  participant CAM as Controlled Approval Modal
  participant DB as Database
  participant ACL as Authority Change Log
  participant SES as Sessions Table
  participant TGT as Target user (next request)

  ADM->>FE: open authority assignments → click Revoke
  FE->>CAM: open modal (password, meaning, reason)
  ADM->>CAM: re-authenticate, state meaning, give reason
  CAM->>API: DELETE /authority/assignments/:id
  API->>DB: BEGIN TRANSACTION
  API->>DB: update assignment status = 'revoked'
  API->>ACL: append AUTHORITY_REVOKED (regulated flag) + hash chain
  API->>DB: increment claims version of target user
  API->>ACL: append CLAIMS_VERSION_INCREMENTED
  alt regulated
    API->>SES: revoke all active sessions of target user
    API->>ACL: append SESSION_REVOKED_AUTHORITY_CHANGE per session
  end
  API->>DB: COMMIT
  API-->>FE: 204
  Note over TGT: target's next refresh
  TGT->>API: POST /auth/refresh
  API-->>TGT: 401 SESSION_REVOKED_AUTHORITY_CHANGE
```

### J-13 — Base-role downgrade forces re-login

- Trigger: administrator reduces a user's base role.
- Steps: the role-change handler writes the role-downgrade event and increments claims version; the user's next refresh returns the dedicated 401 error code.

### J-14 — Delegation creation

- Trigger: a user holding an Authority Profile creates a time-bounded delegation.
- Steps: user submits a delegation referencing target user, profile, scope, effective-from, effective-to (mandatory) and reason; the action is electronically signed; both users' claims versions increment; the target receives the delegation in their next session refresh.

### J-15 — Delegation auto-expiry

- Trigger: scheduled job runs no less frequently than hourly.
- Steps: the system identity transitions every delegation whose end date has passed to expired status, increments both users' claims versions, and emits the expiry event with system attribution.

### J-16 — Account lockout

- Trigger: user fails password verification the configured number of times within the configured window.
- Steps: the back end sets the lockout-until timestamp; further login attempts return the lockout error code with the lockout-until value; an administrator may unlock manually with an electronic signature; the e-mail notification is sent.

### J-17 — IP allowlist denial

- Trigger: a request originates from an IP not in the tenant's allowlist.
- Steps: the back end returns the dedicated error code before the password check; the user interface shows the allowlist message.

### J-18 — Session hijack detection

- Trigger: a request arrives with a valid token but a fingerprint mismatch (different IP-prefix or different normalised user agent).
- Steps: the back end revokes the session, emits the hijack event, and returns the dedicated error code; the user interface clears auth and redirects.

### J-19 — Authority Resolver outage

- Trigger: the Authority Resolver cannot return a context.
- Steps: the back end returns `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` with the user payload, an explicit `authzContextStatus` of `unavailable`, and a correlation identifier; the user remains logged in for read-only paths; the user interface shows the persistent banner; `<AuthorityGuard>` disables every regulated button; the security operations centre receives the alert.

#### Diagram J-19 — Authority Resolver outage handling

```mermaid
sequenceDiagram
  autonumber
  participant FE as Frontend
  participant API as Auth API
  participant AR as Authority Resolver
  participant DB as Database
  participant SOC as Security Operations Centre

  FE->>API: GET /auth/me
  API->>DB: validate session
  API->>AR: resolveAuthzContext
  AR->>DB: read profiles + assignments + delegations + scope rules
  DB-->>AR: error / timeout
  AR-->>API: null + structured error
  API->>DB: append authz_context_resolution_failed
  API->>SOC: critical alert (correlation id)
  API-->>FE: 503 with user identity, status 'unavailable'
  FE->>FE: render persistent banner; disable AuthorityGuard buttons
```

### J-20 — Administrator assigns Authority Profile

- Trigger: tenant administrator opens the user's authority detail page.
- Steps: administrator selects a profile from the catalogue, defines scope, signs the assignment; the back end checks segregation-of-duties rules, writes the assignment, emits the assignment event, and increments the user's claims version.

### J-21 — Administrator revokes Authority Profile

- Trigger: administrator clicks "Revoke".
- Steps: revocation is electronically signed; cascade applies per J-12.

### J-22 — Administrator export of authority change log

- Trigger: administrator opens the audit page and clicks "Export".
- Steps: administrator selects range, filters, format; signs the export with reason; the back end produces a signed download URL with a fifteen-minute time-to-live and a self-verifying integrity manifest.

### J-23 — Permission-denied path for protected route

- Steps: a user without the required permission reaches the route; `<PermissionGuard>` intercepts and renders the access-denied state without issuing an API call.

### J-24 — Validation-error path

- Steps: input that fails validation is rejected inline by the user interface; the back end re-validates server-side and returns 400 with field-level detail when the user interface is bypassed.

### J-25 — System-error and retry path

- Steps: any 5xx response surfaces a non-blocking toast with the correlation identifier; critical paths retry with exponential backoff up to three attempts.

### J-26 — AI-assisted suggestion path

Not applicable. Module 1 contains no AI inference.

### J-27 — Human-in-the-loop approval path

Internal to this module: every administrative authority change is gated by the Controlled Approval Modal and electronic signature.

### J-28 — Offline, session timeout, and conflict path

- Offline: any mutation attempted while the API client detects an offline state is queued in memory only and surfaced to the user; authentication mutations never queue.
- Stale Cross-Site Request Forgery: the back end returns `403 CSRF_INVALID`; the user interface forces a bootstrap call to recover and prompts the user to retry.

---

## 5. Front-End Expected State

### 5.1 Navigation and information architecture

Module 1 contributes the following routes to the application router. Every route below MUST be registered in the router.

| Route | Purpose | Guards |
|---|---|---|
| `/auth/login` | Login form | unauthenticated |
| `/auth/forgot-password` | Forgot-password form | unauthenticated |
| `/auth/reset-password` | Reset-password form (token via query) | unauthenticated |
| `/auth/accept-invite` | Invitation acceptance form | unauthenticated |
| `/auth/mfa/challenge` | Multi-factor challenge | pre-authentication state |
| `/auth/mfa/enroll` | Multi-factor enrolment | authenticated |
| `/auth/change-password` | Force or own password change | authenticated |
| `/auth/tenant-select` | Tenant selection | pre-authentication state |
| `/settings/mfa` | Multi-factor settings | authenticated |
| `/settings/sessions` | Session management | authenticated |
| `/settings/delegations` | Own delegations | authenticated, with permission |
| `/admin/security-policies` | Tenant security policies | authenticated, role gated |
| `/admin/sso` | Single-sign-on configurations | authenticated, role gated |
| `/admin/authority/profiles` | Authority Profile catalogue (Tier 2 management) | authenticated, role gated |
| `/admin/authority/assignments` | Authority assignments | authenticated, role gated |
| `/admin/authority/delegations` | Delegations | authenticated, role gated |
| `/admin/authority/audit` | Authority change log read and export | authenticated, role gated |

### 5.2 Screens

Each screen below MUST implement six states: **loading**, **error**, **success**, **empty**, **permission-restricted**, and **audit-visibility**. Where a state is not applicable to a screen the specification states that explicitly.

#### LoginPage (`/auth/login`)

- Purpose: identify the user; route to multi-factor challenge, tenant selection, change-password, or dashboard.
- Fields: `email` (required), `password` (required, masked), single-sign-on provider buttons (rendered after a debounced lookup against the email).
- Conditional display: single-sign-on provider buttons render only after the lookup query resolves; multi-factor / tenant / force-password-change branches do not display on this page (the page navigates instead).
- Loading: submit button disabled with spinner; lookup query debounced 300 milliseconds.
- Error: inline error region surfaces `INVALID_CREDENTIALS`, `ACCOUNT_LOCKED` (with countdown), `IP_NOT_ALLOWED`, `PASSWORD_EXPIRED` (auto-redirects), `INTERNAL_SERVER_ERROR` with correlation identifier.
- Success: navigate to multi-factor challenge, tenant select, change password, or dashboard depending on the response branch.
- Empty: not applicable.
- Permission-restricted: not applicable (page is unauthenticated).
- Audit visibility: client-only; back end audits the resulting login event.

#### ForgotPasswordPage (`/auth/forgot-password`)

- Purpose: initiate a password-reset e-mail to the user.
- Fields: `email` (required).
- Loading: submit disabled with spinner.
- Error: generic "Could not send reset request — please try again."
- Success: identical confirmation regardless of whether the e-mail exists ("If your email is on file, a link has been sent.") to prevent enumeration.
- Empty / permission-restricted: not applicable.
- Audit visibility: client-only; back end audits `PASSWORD_RESET_REQUESTED`.

#### ResetPasswordPage (`/auth/reset-password`)

- Purpose: complete a password reset using a single-use token from the e-mail link.
- Fields: `token` (from query string, hidden), `newPassword` (required, masked, with live policy indicator), `confirmNewPassword` (required, masked).
- Conditional display: live policy indicator updates as the user types; submit disabled until policy passes and confirm matches.
- Loading: submit disabled with spinner.
- Error: inline `RESET_TOKEN_INVALID`, `PASSWORD_POLICY_VIOLATION` (per-rule list), `PASSWORD_HISTORY_REUSED`.
- Success: navigate to login with success flash; all other sessions of the user have been revoked back-end side.
- Empty / permission-restricted: not applicable.
- Audit visibility: client-only; back end audits `PASSWORD_RESET` and the cascade.

#### AcceptInvitePage (`/auth/accept-invite`)

- Purpose: complete account setup using a single-use invitation token.
- Fields: `token` (from query string, hidden), `password` (required, masked, with live policy indicator), `confirmPassword` (required), terms-acceptance checkbox.
- Loading / Error / Success: as ResetPasswordPage; errors include `INVITE_TOKEN_INVALID`.
- Audit visibility: back end audits `INVITE_ACCEPTED`. Authority Profile is never auto-assigned.

#### MfaChallengePage (`/auth/mfa/challenge`)

- Purpose: collect a six-digit Time-based One-Time Password to complete login.
- Fields: `token` (six-digit numeric, required, auto-submits on the sixth digit).
- Conditional display: shows `attemptsRemaining` only after the first failed attempt; on `MFA_CHALLENGE_EXPIRED` redirects to login with flash.
- Loading: submit disabled with spinner; auto-submit fires once.
- Error: inline `MFA_INVALID_CODE`, `MFA_ATTEMPTS_EXCEEDED`, `MFA_CHALLENGE_EXPIRED`.
- Success: navigate to dashboard.
- Empty: deep-linking without a challenge token in pre-authentication state shows "Your login session has expired. Please log in again." and navigates to `/auth/login`.
- Audit visibility: client-only; back end audits multi-factor events.

#### MfaEnrollPage (`/auth/mfa/enroll`) and MfaSettingsPage (`/settings/mfa`)

- Purpose: enrol or remove the user's multi-factor authentication.
- States: `not_enrolled`, `pending` (display QR code and secret, capture verify code), `active` (display device label and "Disable" with electronic signature), `disabling` (Controlled Approval Modal).
- Fields (enrolment): verify-code field (six-digit numeric).
- Fields (removal): re-authentication via Controlled Approval Modal.
- Conditional display: backup codes are displayed once on successful enrolment and never retrievable again.
- Loading / Error / Success: as above.
- Audit visibility: back end audits `MFA_ENROLL_INITIATED`, `MFA_ENROLLED`, `MFA_REMOVED`.

#### ChangePasswordPage (`/auth/change-password`)

- Purpose: capture a new password (own change or force-change after administrator reset).
- Fields: `currentPassword` (required, masked), `newPassword` (required, masked, with live policy indicator), `confirmNewPassword` (required).
- Conditional display: when `force_password_change` is true, all other navigation is disabled; the page becomes the only reachable screen until completion.
- Loading / Error: inline `INVALID_CURRENT_PASSWORD`, `PASSWORD_POLICY_VIOLATION`, `PASSWORD_HISTORY_REUSED`.
- Success: navigate to dashboard; all other sessions have been revoked back-end side.
- Audit visibility: back end audits `PASSWORD_CHANGE` and the cascade.

#### TenantSelectPage (`/auth/tenant-select`)

- Purpose: select a tenant when the authenticated identity has memberships in more than one active tenant.
- Fields: tenant radio list (required).
- Loading / Error / Success: standard.
- Audit visibility: back end audits `TENANT_SELECTED`.

#### SessionManagementPage (`/settings/sessions`)

- Purpose: list and revoke own active sessions.
- Columns: source IP, parsed device (browser + operating system, derived from user agent), `created_at`, `last_active_at`, `expires_at`, current-device flag, action button "Revoke" (disabled for current session).
- Loading: skeleton list while the query loads.
- Error: standard error state with retry.
- Success: revoked session disappears after invalidation of the sessions query.
- Empty: "No other active sessions for this account."
- Permission-restricted: not applicable; users see only their own sessions.
- Audit visibility: back end audits `SESSION_REVOKE` per action.

#### DelegationManagementPage (`/settings/delegations`)

- Purpose: list, create, and revoke own delegations.
- Columns: from / to / Authority Profile / scope summary / `effective_from` / `effective_to` / status badge (`active`, `expired`, `revoked`) / actions.
- Action: "Create delegation" opens a modal for selecting profile, target user, scope (seven-dimension chips with `tenant_wide` toggle), `effective_from`, `effective_to` (mandatory non-null), reason.
- Action: "Revoke" opens the Controlled Approval Modal.
- Loading / Error / Success / Empty: standard.
- Permission-restricted: only delegations the user is a party to are shown.
- Audit visibility: back end audits `DELEGATION_CREATED`, `DELEGATION_REVOKED`.

#### AdminSecurityPoliciesPage (`/admin/security-policies`)

- Purpose: tenant administration of security policies.
- Tabs: Password Policy, Session Policy, Lockout Policy, IP Allowlist, Multi-Factor Policy.
- Each tab: read view with current values, edit form with policy-specific fields, "Save" routed through Controlled Approval Modal.
- Conditional display: edit form fields per tab as listed in §5.3.
- Loading / Error / Success: standard.
- Permission-restricted: viewers see read-only summary; editing requires `tenant_admin_authority`.
- Audit visibility: back end audits `POLICY_UPDATED` per save.

#### AdminSsoConfigPage (`/admin/sso`)

- Purpose: list, create, update, delete tenant single-sign-on configurations.
- Fields per configuration: provider type (OpenID Connect or Security Assertion Markup Language), client identifier, client secret (masked, write-only), endpoint URLs, attribute mappings, "Test connection" non-mutating button.
- Action: create / update / delete routed through Controlled Approval Modal.
- Loading / Error / Success / Empty: standard.
- Permission-restricted: requires `tenant_admin_authority`.
- Audit visibility: back end audits `SSO_CONFIG_CREATED`, `SSO_CONFIG_UPDATED`, `SSO_CONFIG_DELETED`.

#### AdminAuthorityProfilesPage (`/admin/authority/profiles`)

- Purpose: read the catalogue (Tier 1 + Tier 2); create, update, deactivate Tier 2 (tenant-defined) Authority Profiles.
- Columns: key, label, description, regulated flag, requires-electronic-signature flag, allows-delegation flag, scope dimensions, status, version.
- Action: "Create Tier 2 profile" opens a form (key, label, description, regulated flag, requires-electronic-signature flag, allows-delegation flag, allowed scope dimensions). Submit routed through Controlled Approval Modal. Tier 1 (global) profile rows are read-only here; Tier 1 catalogue editing requires `platform_admin` and is on a separate platform admin surface.
- Loading / Error / Success: standard.
- Permission-restricted: viewers blocked at the route guard; tenant administrators may create Tier 2 only.
- Audit visibility: back end audits `AUTHORITY_PROFILE_CREATED`, `AUTHORITY_PROFILE_UPDATED`, `AUTHORITY_PROFILE_DEACTIVATED`.

#### AdminAuthorityAssignmentsPage (`/admin/authority/assignments`)

- Purpose: assign and revoke Authority Profiles for users.
- Columns: user, profile, scope summary, `effective_from`, `effective_to`, status, actions.
- Action: "Assign" opens a form (user picker, profile picker, scope chips, effective dates, reason); submit routed through Controlled Approval Modal. "Revoke" opens the Controlled Approval Modal directly.
- Conditional display: a warning banner displays the cascade effect of revoking a regulated profile ("This will revoke all active sessions of [user]").
- Loading / Error / Success / Empty: standard.
- Permission-restricted: requires `tenant_admin_authority`.
- Audit visibility: back end audits `AUTHORITY_ASSIGNED`, `AUTHORITY_REVOKED`, `CLAIMS_VERSION_INCREMENTED`.

#### AdminAuthorityDelegationsPage (`/admin/authority/delegations`)

- Purpose: tenant-wide view of all delegations across the tenant.
- Columns: as DelegationManagementPage plus full user names.
- Action: administrator may revoke any user's delegation through the Controlled Approval Modal.
- Loading / Error / Success / Empty: standard.
- Permission-restricted: requires `tenant_admin_authority`.
- Audit visibility: back end audits `DELEGATION_REVOKED`.

#### AdminAuthorityAuditPage (`/admin/authority/audit`)

- Purpose: read and export the authority change log; verify hash-chain integrity.
- Columns: row identifier, action, actor, target, profile, scope before, scope after, reason, electronic-signature identifier, claims version after, previous hash, record hash, timestamp.
- Conditional display: an integrity badge per chain segment ("verified" or "broken — alert raised").
- Action: "Export" opens a form (range, filters, format: CSV / PDF / JSON-Lines); submit routed through Controlled Approval Modal; back end returns a signed download URL with fifteen-minute time-to-live and a self-verifying integrity manifest.
- Loading / Error / Success / Empty: standard.
- Permission-restricted: requires `tenant_admin_authority`.
- Audit visibility: back end audits `AUTHORITY_LOG_EXPORTED`.

### 5.3 Forms and field rules

Every form validates input against published schemas. Where the database column is non-null the corresponding form field is required (no `optional`, no `nullable`). The back end re-validates every state-changing request server-side. The table below enumerates every field collected by Module 1's user interface.

| Field identifier | Label | Type | Required | Validation | Source | Editability by status | Audit requirement | Regulatory relevance |
|---|---|---|---|---|---|---|---|---|
| `email` | Email | string | Yes | RFC 5322 + `.email()` + `.max(254)` | user input | always | not logged | 21 CFR Part 11 §11.10(d) |
| `password` (login) | Password | string (masked) | Yes | `.min(1)` (existing-credential check is server-side) | user input | always | never logged | 21 CFR Part 11 §11.300 |
| `newPassword` (change / reset / accept-invite) | New password | string (masked) | Yes | server-policy + `.min(policy.minLength)` + class composition (uppercase / lowercase / number / special character per policy) + history check | user input | when on change / reset / accept-invite | never logged | 21 CFR Part 11 §11.300 |
| `confirmNewPassword` | Confirm new password | string (masked) | Yes | `.refine(equal)` against `newPassword` | user input | with `newPassword` | never logged | 21 CFR Part 11 §11.300 |
| `token` (multi-factor) | Authenticator code | string | Yes | `.length(6).regex(/^\d+$/)` | user input | multi-factor challenge | not logged | 21 CFR Part 11 §11.10(g) |
| `mfaChallenge` | Challenge token | string | Yes | server-issued, `.uuid()` | server response | hidden | not logged | 21 CFR Part 11 §11.10(g) |
| `forgotEmail` | Email | string | Yes | `.email()` | user input | always | not logged | 21 CFR Part 11 §11.300 |
| `resetToken` | Reset token | string | Yes | `.min(1)` | URL query | hidden | not logged | 21 CFR Part 11 §11.300 |
| `inviteToken` | Invite token | string | Yes | `.min(1)` | URL query | hidden | not logged | not applicable |
| `tenantId` (tenant select) | Tenant | string | Yes | `.uuid()` from response options | server response | tenant select | yes (`TENANT_SELECTED`) | EU GMP Annex 11 §12 |
| `delegationFromUserId` | Delegator | string | Yes | `.uuid()` (must be self for non-administrator) | server | delegation create | yes | EU GMP Annex 11 §12 |
| `delegationToUserId` | Delegate | string | Yes | `.uuid()`; delegate must be active member | server | delegation create | yes | EU GMP Annex 11 §12 |
| `authorityProfileKey` | Authority Profile | string | Yes | server enum (catalogue) | catalogue | delegation / assignment | yes | EU GMP Annex 11 §12 |
| `effectiveFrom` | Effective from | datetime | Yes | `.datetime()` ≥ now | user input | always | yes | 21 CFR Part 11 §11.10(e) |
| `effectiveTo` | Effective to | datetime | Yes (delegations) / Optional (assignments) | `.datetime()` strictly greater than `effectiveFrom`; for delegations cannot exceed delegator's own `effective_to` | user input | always | yes | 21 CFR Part 11 §11.10(e) |
| `scopeRestriction` | Scope (seven dimensions + tenant-wide) | object | Conditional per profile | each dimension is array of UUIDs (sites, products, studies, suppliers, modules, entity types, workflow types) or `tenantWide: true` | user input | always | yes | EU GMP Annex 11 §12 |
| `reasonForChange` | Reason | string | Yes (regulated mutations) | `.min(8).max(2000)` | user input | always | yes | 21 CFR Part 11 §11.10(e) |
| `meaningOfSignature` | Meaning of signature | string | Yes (regulated mutations) | `.min(8).max(500)` | user input | regulated mutations | yes | 21 CFR Part 11 §11.100 |
| `currentPassword` | Current password | string (masked) | Yes (change password / multi-factor remove) | `.min(1)` | user input | password change / multi-factor remove | never logged | 21 CFR Part 11 §11.300 |
| `passwordPolicy.minLength` | Minimum length | integer | Yes (admin) | `.int().min(8)` | user input | administrator policy edit | yes (`POLICY_UPDATED`) | 21 CFR Part 11 §11.300 |
| `passwordPolicy.historyCount` | History count | integer | Yes (admin) | `.int().min(0).max(24)` | user input | administrator policy edit | yes | 21 CFR Part 11 §11.300 |
| `sessionPolicy.idleTimeoutMinutes` | Idle timeout (minutes) | integer | Yes (admin) | `.int().min(5).max(480)` | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `lockoutPolicy.maxAttempts` | Max attempts | integer | Yes (admin) | `.int().min(3).max(10)` | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `lockoutPolicy.windowMinutes` | Failure window (minutes) | integer | Yes (admin) | `.int().min(1).max(60)` | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `lockoutPolicy.lockoutDurationMinutes` | Lockout duration (minutes) | integer | Yes (admin) | `.int().min(1).max(120)` | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `ipAllowlist.cidr` | CIDR | string | Yes (admin) | RFC 4632 / 5952 CIDR notation; IPv4 or IPv6 | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `ipAllowlist.description` | Description | string | Yes (admin) | `.min(8).max(500)` | user input | administrator policy edit | yes | EU GMP Annex 11 §12 |
| `ssoConfig.provider` | Provider | enum | Yes (admin) | `'oidc' \| 'saml'` | user input | administrator config edit | yes | EU GMP Annex 11 §12 |
| `ssoConfig.clientId` | Client identifier | string | Yes (admin) | `.min(1)` | user input | administrator config edit | yes | EU GMP Annex 11 §12 |
| `ssoConfig.clientSecret` | Client secret | string (masked, write-only) | Yes (admin) | `.min(1)` | user input | administrator config edit | yes (value never logged) | 21 CFR Part 11 §11.10(d) |
| `ssoConfig.endpoints` | Endpoint URLs | object | Yes (admin) | each URL `.url()` | user input | administrator config edit | yes | EU GMP Annex 11 §12 |
| `authorityProfile.key` | Profile key | string | Yes (Tier 2) | `.min(2).max(64).regex(/^[a-z][a-z0-9_]*$/)` | user input | Tier 2 create | yes | EU GMP Annex 11 §12 |
| `authorityProfile.label` | Profile label | string | Yes (Tier 2) | `.min(3).max(120)` | user input | Tier 2 create / update | yes | EU GMP Annex 11 §12 |
| `authorityProfile.description` | Profile description | string | Yes (Tier 2) | `.min(8).max(2000)` | user input | Tier 2 create / update | yes | EU GMP Annex 11 §12 |
| `authorityProfile.regulated` | Regulated | boolean | Yes (Tier 2) | strict boolean | user input | Tier 2 create | yes | EU GMP Annex 11 §12 |
| `authorityProfile.requiresEsign` | Requires electronic signature | boolean | Yes (Tier 2) | strict boolean; cannot be false when `regulated = true` | user input | Tier 2 create / update | yes | 21 CFR Part 11 §11.100 |
| `authorityProfile.allowsDelegation` | Allows delegation | boolean | Yes (Tier 2) | strict boolean | user input | Tier 2 create / update | yes | EU GMP Annex 11 §12 |

### 5.4 User-interface state machines

#### Diagram 5.4-A — Session lifecycle state machine

```mermaid
stateDiagram-v2
  [*] --> created: login / multi-factor complete / single-sign-on callback
  created --> active: cookies set + session row persisted
  active --> revoked: self revoke
  active --> revoked: administrator revoke
  active --> revoked: claims-version critical change at refresh
  active --> revoked: hijack detected (fingerprint mismatch)
  active --> revoked: refresh-token reuse detected
  active --> revoked: password change or reset cascade
  active --> expired: idle timeout
  active --> expired: absolute timeout
  revoked --> [*]
  expired --> [*]
```

#### Diagram 5.4-B — Authority Assignment lifecycle

```mermaid
stateDiagram-v2
  [*] --> active: administrator assigns (electronic signature)
  active --> revoked: administrator revokes (electronic signature)
  active --> expired: system identity (effective_to passed)
  revoked --> [*]
  expired --> [*]
```

#### Diagram 5.4-C — Delegation lifecycle

```mermaid
stateDiagram-v2
  [*] --> active: delegator or administrator creates (electronic signature; effective_to mandatory)
  active --> revoked: delegator or administrator revokes (electronic signature)
  active --> expired: system identity at effective_to
  revoked --> [*]
  expired --> [*]
```

#### Diagram 5.4-D — Multi-factor enrolment lifecycle

```mermaid
stateDiagram-v2
  [*] --> pending: user begins enrolment
  pending --> active: user verifies first code
  pending --> [*]: time-out or cancel
  active --> removed: user removes (electronic signature with re-authentication)
  removed --> [*]
```

### 5.5 User-interface safety controls

Confirmation modals appear before every irreversible action and name the user, scope, and downstream effect. Submit controls are disabled during async submission to prevent double submission. The forgot-password screen returns the same response shape regardless of whether the e-mail exists, to prevent enumeration. The change-password screen blocks every other navigation when the force-password-change flag is true. The session-timeout warning surfaces two minutes before idle expiry. The Cross-Site Request Forgery error path forces a bootstrap call rather than silent retry.

---

## 6. Back-End Expected State

### 6.1 Domain entities

Users, memberships, sessions, refresh tokens, multi-factor enrolments, multi-factor challenges, password policies, password history, password reset tokens, account lockouts, IP allowlists, session policies, single-sign-on configurations, single-sign-on state tokens, authentication audit log, Authority Profiles, user authority assignments, approval delegations, authority scope rules, segregation-of-duties rules, user-tenant authorisation state (claims-version counter), authority change log, failed-operation log.

### 6.1.1 Diagram 6.1-A — Module 1 data model (entity-relationship overview)

```mermaid
erDiagram
  TENANTS ||--o{ MEMBERSHIPS : has
  USERS ||--o{ MEMBERSHIPS : has
  USERS ||--o{ USER_SESSIONS : owns
  USER_SESSIONS ||--|| REFRESH_TOKENS : pairs
  USERS ||--o{ MFA_ENROLLMENTS : has
  USERS ||--o{ MFA_CHALLENGES : has
  USERS ||--o{ PASSWORD_HISTORY : has
  USERS ||--o{ PASSWORD_RESET_TOKENS : has
  USERS ||--|| ACCOUNT_LOCKOUTS : has
  TENANTS ||--|| PASSWORD_POLICIES : has
  TENANTS ||--|| SESSION_POLICIES : has
  TENANTS ||--o{ IP_ALLOWLISTS : has
  TENANTS ||--o{ SSO_CONFIGURATIONS : has
  SSO_CONFIGURATIONS ||--o{ SSO_STATE_TOKENS : issues
  AUTHORITY_PROFILES ||--o{ USER_AUTHORITY_ASSIGNMENTS : grants
  AUTHORITY_PROFILES ||--o{ AUTHORITY_SCOPE_RULES : constrains
  USERS ||--o{ USER_AUTHORITY_ASSIGNMENTS : holds
  USERS ||--o{ APPROVAL_DELEGATIONS : delegator
  USERS ||--o{ APPROVAL_DELEGATIONS : delegate
  AUTHORITY_PROFILES ||--o{ APPROVAL_DELEGATIONS : delegates
  USERS ||--|| USER_TENANT_AUTHZ_STATE : counter
  TENANTS ||--o{ USER_TENANT_AUTHZ_STATE : within
  USERS ||--o{ AUTH_AUDIT_LOG : actor
  USERS ||--o{ AUTHORITY_CHANGE_LOG : actor
  USERS ||--o{ AUTHORITY_CHANGE_LOG : target
  ELECTRONIC_SIGNATURES ||--o{ AUTH_AUDIT_LOG : signed_by
  ELECTRONIC_SIGNATURES ||--o{ AUTHORITY_CHANGE_LOG : signed_by
```

### 6.2 Data model requirements

The table below lists every entity in scope. **Tenant isolation** is universal — every table has Row-Level Security enabled in the same migration that creates it. **Append-only logs** deny UPDATE and DELETE at the database role level. **Versioned tables** retain history through a `version` column with `effective_from` and `effective_to`. Retention values shown are minimums; rows MAY move to cold storage after two years subject to the retrieval service-level agreement of URS-35.

| Entity | Purpose | Key fields | Required | Unique constraints | Tenant isolation | Versioning | Retention | Soft-delete | Audit | E-signature link |
|---|---|---|---|---|---|---|---|---|---|---|
| `users` | Identity | `id`, `email`, `first_name`, `last_name`, `status`, `created_at`, `force_password_change`, `deleted_at` | `id`, `email`, `status` | unique(`email`) | RLS via `memberships` join | none | seven years post-deactivation | yes (`deleted_at`) | yes | not applicable |
| `memberships` | User × tenant × base role | `id`, `user_id`, `tenant_id`, `role`, `status`, `external_type` (nullable) | all | unique(`user_id`, `tenant_id`) | RLS on `tenant_id` | none | seven years | yes | yes | yes (role changes) |
| `user_sessions` | Active session row | `id`, `user_id`, `tenant_id`, `refresh_token_id`, `claims_version`, `last_active_at`, `expires_at`, `fingerprint_ip_prefix`, `fingerprint_ua_norm`, `status`, `revoked_by`, `revoked_reason` | all | unique(`refresh_token_id`) | RLS on `tenant_id` | none | ninety days post-expiry | hard (after retention) | yes | not applicable |
| `refresh_tokens` | Refresh token (hashed) | `id`, `user_session_id`, `token_hash`, `issued_at`, `expires_at`, `revoked_at` | all | unique(`token_hash`) | RLS via session join | none | ninety days post-revoke | hard | yes | not applicable |
| `mfa_enrollments` | TOTP enrolment | `id`, `user_id`, `secret_encrypted`, `status`, `enrolled_at`, `last_used_at` | `id`, `user_id`, `status` | unique(`user_id`) where `status='active'` | RLS via membership | none | retain while active; ninety days after removal | yes | yes | yes (enrol / remove) |
| `mfa_challenges` | Challenge state | `id`, `mfa_challenge_token`, `user_id`, `attempts`, `max_attempts`, `expires_at`, `completed_at` | all | unique(`mfa_challenge_token`) | platform-context RLS (pre-auth) | none | twenty-four hours | hard | yes | not applicable |
| `password_policies` | Per-tenant password policy | `tenant_id`, `min_length`, `require_uppercase`, `require_lowercase`, `require_number`, `require_special`, `history_count`, `max_age_days`, `expiry_warning_days`, `version`, `effective_from`, `effective_to` | `tenant_id`, all policy fields | unique(`tenant_id`, `version`) | RLS on `tenant_id` | versioned | retain all versions | not applicable | yes | yes (administrator edit) |
| `password_history` | Hashes for re-use prevention | `id`, `user_id`, `password_hash`, `created_at` | all | none | RLS via membership | append | per `historyCount` | hard (FIFO) | yes | not applicable |
| `password_reset_tokens` | One-time reset | `id`, `user_id`, `token_hash`, `expires_at`, `used_at` | all | unique(`token_hash`) | RLS via membership | none | twenty-four hours | hard | yes | not applicable |
| `account_lockouts` | Per-user lockout state | `id`, `user_id`, `failed_attempts`, `locked_until`, `last_failure_ip`, `last_failure_ua` | all | unique(`user_id`) | RLS via membership | none | ninety days | hard | yes | yes (administrator unlock) |
| `ip_allowlists` | CIDR list | `id`, `tenant_id`, `cidr`, `description`, `created_by`, `version`, `effective_from`, `effective_to` | all | unique(`tenant_id`, `cidr`, `version`) | RLS on `tenant_id` | versioned | retain history | yes | yes | yes (administrator edit) |
| `session_policies` | Per-tenant session policy | `tenant_id`, `idle_timeout_minutes`, `absolute_timeout_minutes`, `mfa_for_all`, `hijack_strict`, `version`, `effective_from`, `effective_to` | all | unique(`tenant_id`, `version`) | RLS on `tenant_id` | versioned | retain history | not applicable | yes | yes (administrator edit) |
| `sso_configurations` | Per-tenant identity-provider configuration | `id`, `tenant_id`, `provider`, `client_id`, `client_secret_encrypted`, `endpoints`, `attribute_mappings`, `status`, `version`, `effective_from`, `effective_to` | all | unique(`tenant_id`, `provider`, `version`) | RLS on `tenant_id` | versioned | retain history | yes | yes | yes (administrator edit) |
| `sso_state_tokens` | OAuth / SAML state | `id`, `state`, `nonce`, `tenant_id`, `provider`, `expires_at` | all | unique(`state`) | platform-context RLS | none | fifteen minutes | hard | not applicable (transient) | not applicable |
| `auth_audit_log` | Hash-chained authentication events | `id`, `user_id`, `tenant_id`, `event`, `ip`, `user_agent`, `metadata jsonb`, `previous_hash`, `record_hash`, `created_at` | `id`, `event`, `created_at`, `record_hash` | unique(`record_hash`) | RLS on `tenant_id` (NULL allowed for pre-auth) | none | seven years | append-only | self | not applicable |
| `authority_profiles` | Profile catalogue (Tier 1 + Tier 2) | `id`, `tenant_id` (nullable), `key`, `label`, `description`, `regulated`, `requires_esign`, `requires_dual_sign`, `allows_override`, `allows_delegation`, `effective_from`, `effective_to`, `is_system`, `version` | `id`, `key` | unique(coalesce(`tenant_id`, system-uuid), `key`) | RLS on `tenant_id` with NULL fallback | versioned | retain | yes | yes | yes (catalogue edits) |
| `user_authority_assignments` | Authority grant | `id`, `user_id`, `tenant_id`, `authority_profile_id`, `status`, `scope_restriction jsonb`, `effective_from`, `effective_to` (nullable), `created_by`, `revoked_by`, `revoked_at` | `id`, `user_id`, profile, status, `effective_from` | unique active(`user_id`, profile, scope-hash) | RLS on `tenant_id` | none | seven years | yes | yes | yes |
| `approval_delegations` | Delegation grant | `id`, `from_user_id`, `to_user_id`, `tenant_id`, `authority_profile_id`, `scope_restriction jsonb`, `status`, `effective_from`, `effective_to` (NOT NULL), `reason`, `created_by`, `revoked_by`, `revoked_at` | all | unique active(from, to, profile, scope-hash, `effective_from`) | RLS on `tenant_id` | none | seven years | yes | yes | yes |
| `authority_scope_rules` | Per-profile scope rules | `id`, `authority_profile_id`, `dimension` (enum), `allowed_values jsonb`, `version` | all | none | RLS via profile | versioned | retain | yes | yes | yes |
| `sod_rules` | Segregation-of-Duties rule registry | `id`, `tenant_id` (nullable), `rule_type`, `entity_type`, `prior_action`, `node_action`, `description`, `is_active` | all | none | RLS on `tenant_id` | versioned | retain | yes | yes | yes |
| `user_tenant_authz_state` | Claims-version counter | `user_id`, `tenant_id`, `claims_version`, `last_incremented_at` | all | unique(`user_id`, `tenant_id`) | RLS on `tenant_id` | counter | retain | not applicable | yes | not applicable |
| `authority_change_log` | Hash-chained authority events | `id`, `action` (enum from twelve-event vocabulary), `actor_user_id` (nullable for system actor), `target_user_id`, `tenant_id`, `profile_id`, `scope_before`, `scope_after`, `reason`, `e_sig_id` (nullable), `claims_version_after`, `previous_hash`, `record_hash`, `created_at` | `id`, `action`, `created_at`, `record_hash` | unique(`record_hash`) | RLS on `tenant_id` | none | twenty-five years | append-only | self | linked when actor is user-driven |
| `electronic_signatures` (referenced; owned by URS-04) | Signature record | `id`, `signed_by`, `ip`, `user_agent`, `signed_at`, `meaning`, `reason`, `content_snapshot`, `invalidated_at` | all | none | RLS on `tenant_id` | none | seven years | not applicable | yes | self |
| `failed_operation_log` | Non-fatal failed actions | `id`, `operation`, `error_code`, `payload_hash`, `user_id`, `tenant_id`, `created_at` | all | none | RLS on `tenant_id` | none | ninety days | hard | yes | not applicable |

### 6.3 API requirements

Every mutation requires the Cross-Site Request Forgery token header. Every endpoint returns a correlation identifier on response. The table below enumerates every endpoint Module 1 owns.

#### 6.3.1 Authentication and session core

| Method | Endpoint | Actor | Request | Response | Validation | Permission | Audit event(s) | Error codes | Idempotency | Rate limit | Downstream |
|---|---|---|---|---|---|---|---|---|---|---|---|
| POST | `/auth/login` | unauthenticated | `{email, password}` | `LoginResponse` or `MfaRequiredResponse` or `TenantSelectionResponse` or `{requiresPasswordChange:true,…}` | Zod | none | `LOGIN_SUCCESS` / `LOGIN_FAILURE` / `MFA_CHALLENGE` / `AUTHZ_CONTEXT_RESOLVED` | `INVALID_CREDENTIALS`, `ACCOUNT_LOCKED`, `IP_NOT_ALLOWED`, `PASSWORD_EXPIRED`, `MFA_REQUIRED` (200), `AUTHZ_CONTEXT_RESOLUTION_FAILED` (503) | non-idempotent | 10/min/IP, 30/hour/account | mints session + refresh + cookies |
| POST | `/auth/mfa/complete` | pre-auth (challenge) | `{mfaChallenge, token}` | `LoginResponse` | Zod | challenge-state | `MFA_SUCCESS` / `MFA_FAILURE` / `LOGIN_SUCCESS` / `AUTHZ_CONTEXT_RESOLVED` | `MFA_INVALID_CODE`, `MFA_CHALLENGE_EXPIRED`, `MFA_ATTEMPTS_EXCEEDED`, `AUTHZ_CONTEXT_RESOLUTION_FAILED` | non-idempotent | 10/min/(challenge,IP) | mints session |
| POST | `/auth/refresh` | refresh-cookie | none | `LoginResponse` (rotated tokens) | none | refresh-token validity | `TOKEN_REFRESH` / `SESSION_REVOKED_AUTHORITY_CHANGE` / `AUTHZ_CONTEXT_RESOLVED` | `TOKEN_EXPIRED`, `TOKEN_REUSE_DETECTED`, `SESSION_REVOKED`, `CLAIMS_VERSION_MISMATCH`, `SESSION_REVOKED_AUTHORITY_CHANGE` | rotating | 60/min/session | rotates refresh; may revoke session |
| POST | `/auth/logout` | authenticated | none | `204` | none | self | `LOGOUT` | none | idempotent | not applicable | clears cookies; revokes session |
| GET | `/auth/me` | authenticated | none | `LoginResponse` (regenerated CSRF) or `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` | none | self | `AUTHZ_CONTEXT_RESOLVED` | `AUTHZ_CONTEXT_RESOLUTION_FAILED` | safe (GET) | 60/min/user | regenerates CSRF |
| POST | `/auth/forgot-password` | unauthenticated | `{email}` | `200 {sent:true}` (always — anti-enumeration) | Zod | none | `PASSWORD_RESET_REQUESTED` | none | non-idempotent (token issued) | 5/min/IP | sends e-mail |
| POST | `/auth/reset-password` | unauthenticated | `{token, newPassword}` | `200 {ok:true}` | Zod + policy | token validity | `PASSWORD_RESET` / `SESSION_REVOKE_PASSWORD_CHANGE` (cascade) | `RESET_TOKEN_INVALID`, `PASSWORD_POLICY_VIOLATION`, `PASSWORD_HISTORY_REUSED` | single-use | 5/min/IP | revokes all sessions |
| POST | `/auth/change-password` | authenticated | `{currentPassword, newPassword}` | `200 {ok:true}` | Zod + policy | self | `PASSWORD_CHANGE` / `SESSION_REVOKE_PASSWORD_CHANGE` (cascade) | `INVALID_CURRENT_PASSWORD`, `PASSWORD_POLICY_VIOLATION`, `PASSWORD_HISTORY_REUSED` | non-idempotent | 5/min/user | revokes all other sessions |
| POST | `/auth/accept-invite` | invite-token | `{token, password}` | `LoginResponse` | Zod + policy | token validity | `INVITE_ACCEPTED` | `INVITE_TOKEN_INVALID`, `PASSWORD_POLICY_VIOLATION` | single-use | 5/min/IP | mints session |

#### 6.3.2 Sessions

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes | Idempotency | Rate limit |
|---|---|---|---|---|---|---|---|---|---|
| GET | `/auth/sessions` | authenticated | none | `Session[]` | self | none (read) | none | safe | 30/min/user |
| DELETE | `/auth/sessions/:id` | authenticated | none | `204` | self | `SESSION_REVOKE` | `SESSION_NOT_FOUND` | idempotent | 10/min/user |
| DELETE | `/auth/sessions` | authenticated | none | `204` | self | `SESSION_REVOKE_ALL` | none | idempotent | 10/min/user |
| POST | `/auth/admin/sessions/:userId/revoke-all` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `SESSION_REVOKE_ADMIN` | `USER_NOT_FOUND` | idempotent | 60/min/admin |

#### 6.3.3 Multi-factor authentication

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes | Idempotency | Rate limit |
|---|---|---|---|---|---|---|---|---|---|
| GET | `/auth/mfa/status` | authenticated | none | `{enrolled, method, enrolledAt}` | self | none | none | safe | 30/min/user |
| POST | `/auth/mfa/enroll` | authenticated | none | `{secret, qrCodeUri, backupCodes[]}` | self | `MFA_ENROLL_INITIATED` | `MFA_ALREADY_ENROLLED` | non-idempotent | 5/min/user |
| POST | `/auth/mfa/enroll/verify` | authenticated | `{token}` | `204` | self | `MFA_ENROLLED` | `MFA_INVALID_CODE` | non-idempotent | 10/min/user |
| DELETE | `/auth/mfa/enroll` | authenticated | `{password, reason}` (electronic-signed) | `204` | self | `MFA_REMOVED` | `INVALID_CURRENT_PASSWORD` | idempotent | 5/min/user |

#### 6.3.4 Single sign-on

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes | Idempotency | Rate limit |
|---|---|---|---|---|---|---|---|---|---|
| GET | `/auth/sso/:provider` | unauthenticated | none | `302` to identity provider | none | none | none | safe (redirect) | 60/min/IP |
| GET | `/auth/sso/:provider/callback` | unauthenticated | provider params | `302` to `${FRONTEND_URL}/` | state validity | `LOGIN_SUCCESS` / `LOGIN_FAILURE` / `AUTHZ_CONTEXT_RESOLVED` | `SSO_STATE_INVALID`, `SSO_PROVIDER_ERROR`, `AUTHZ_CONTEXT_RESOLUTION_FAILED` | single-use state | 60/min/IP |
| GET | `/auth/sso/configurations` | administrator | none | `SsoConfig[]` | `tenant_admin_authority` | none | none | safe | 30/min/admin |
| POST | `/auth/sso/configurations` | administrator | `SsoConfig` (electronic-signed) | `201 SsoConfig` | `tenant_admin_authority` | `SSO_CONFIG_CREATED` | `SSO_CONFIG_INVALID` | non-idempotent | 30/min/admin |
| PUT | `/auth/sso/configurations/:id` | administrator | `SsoConfig` (electronic-signed) | `200` | `tenant_admin_authority` | `SSO_CONFIG_UPDATED` | as above | non-idempotent | 30/min/admin |
| DELETE | `/auth/sso/configurations/:id` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `SSO_CONFIG_DELETED` | `SSO_CONFIG_NOT_FOUND` | idempotent | 10/min/admin |

#### 6.3.5 Security policies

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes |
|---|---|---|---|---|---|---|---|
| GET | `/auth/policies/password` | authenticated | none | `PasswordPolicy` | self | none | none |
| PUT | `/auth/policies/password` | administrator | `PasswordPolicy` (electronic-signed) | `200` | `tenant_admin_authority` | `POLICY_UPDATED` | `POLICY_INVALID` |
| GET | `/auth/policies/session` | authenticated | none | `SessionPolicy` | self | none | none |
| PUT | `/auth/policies/session` | administrator | `SessionPolicy` (electronic-signed) | `200` | `tenant_admin_authority` | `POLICY_UPDATED` | `POLICY_INVALID` |
| GET | `/auth/policies/lockout` | authenticated | none | `LockoutPolicy` | self | none | none |
| PUT | `/auth/policies/lockout` | administrator | `LockoutPolicy` (electronic-signed) | `200` | `tenant_admin_authority` | `POLICY_UPDATED` | `POLICY_INVALID` |
| GET | `/auth/policies/ip-allowlist` | authenticated | none | `IpAllowlist[]` | self | none | none |
| POST | `/auth/policies/ip-allowlist` | administrator | `{cidr, description}` (electronic-signed) | `201` | `tenant_admin_authority` | `IP_ALLOWLIST_ADDED` | `CIDR_INVALID` |
| DELETE | `/auth/policies/ip-allowlist/:id` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `IP_ALLOWLIST_REMOVED` | `NOT_FOUND` |

#### 6.3.6 Authority management

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes |
|---|---|---|---|---|---|---|---|
| GET | `/authority/profiles` | administrator | none | `AuthorityProfile[]` | `tenant_admin_authority` | none | none |
| POST | `/authority/profiles` | platform-administrator (Tier 1) or tenant administrator (Tier 2) | `AuthorityProfile` (electronic-signed) | `201` | platform admin (Tier 1) or `tenant_admin_authority` (Tier 2) | `AUTHORITY_PROFILE_CREATED` | `PROFILE_KEY_DUPLICATE` |
| PUT | `/authority/profiles/:id` | platform-administrator (Tier 1) or tenant administrator (Tier 2) | `AuthorityProfile` (electronic-signed) | `200` | as above | `AUTHORITY_PROFILE_UPDATED` | `PROFILE_KEY_DUPLICATE`, `KEY_IMMUTABLE_AFTER_REFERENCE` |
| DELETE | `/authority/profiles/:id` | as above | `{reason}` (electronic-signed) | `204` | as above | `AUTHORITY_PROFILE_DEACTIVATED` | `PROFILE_IN_USE`, `IS_SYSTEM_PROFILE` |
| GET | `/authority/assignments` | administrator | filters | `Assignment[]` | `tenant_admin_authority` | none | none |
| POST | `/authority/assignments` | administrator | `{user_id, profile_key, scope, effective_from, effective_to?, reason}` (electronic-signed) | `201` | `tenant_admin_authority` (with self-modification block) | `AUTHORITY_ASSIGNED` + `CLAIMS_VERSION_INCREMENTED` | `SOD_VIOLATION`, `PROFILE_NOT_FOUND`, `SCOPE_INVALID` |
| DELETE | `/authority/assignments/:id` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `AUTHORITY_REVOKED` + `CLAIMS_VERSION_INCREMENTED` (+ session revoke if regulated) | `NOT_FOUND` |
| GET | `/authority/delegations` | self / administrator | filters | `Delegation[]` | self / `tenant_admin_authority` | none | none |
| POST | `/authority/delegations` | self / administrator | `{from_user_id, to_user_id, profile_key, scope, effective_from, effective_to, reason}` (electronic-signed) | `201` | self if `from = self` else `tenant_admin_authority`; SoD self-check | `DELEGATION_CREATED` + `CLAIMS_VERSION_INCREMENTED` (both users) | `DELEGATION_INVALID`, `SOD_VIOLATION`, `PROFILE_NOT_FOUND` |
| DELETE | `/authority/delegations/:id` | self / administrator | `{reason}` (electronic-signed) | `204` | self if `from = self` else `tenant_admin_authority` | `DELEGATION_REVOKED` + `CLAIMS_VERSION_INCREMENTED` (both users) | `NOT_FOUND` |
| GET | `/authority/me` | authenticated | none | `AuthzContext` | self | `AUTHZ_CONTEXT_RESOLVED` | `AUTHZ_CONTEXT_RESOLUTION_FAILED` |
| GET | `/authority/users/:userId` | administrator | none | `AuthzContext` | `tenant_admin_authority` | `AUTHZ_CONTEXT_RESOLVED` | `USER_NOT_FOUND`, `AUTHZ_CONTEXT_RESOLUTION_FAILED` |
| GET | `/authority/scope-rules` | administrator | filters | `ScopeRule[]` | `tenant_admin_authority` | none | none |
| POST/PUT/DELETE | `/authority/scope-rules[/:id]` | platform-administrator | `ScopeRule` (electronic-signed) | `201/200/204` | platform admin | `SCOPE_RULE_*` | `SCOPE_INVALID` |
| GET | `/authority/sod-rules` | administrator | none | `SodRule[]` | `tenant_admin_authority` | none | none |
| POST/PUT/DELETE | `/authority/sod-rules[/:id]` | platform-administrator | `SodRule` (electronic-signed) | `201/200/204` | platform admin | `SOD_RULE_*` | none |
| POST | `/authority/check` | server-side hook only | `{profile_key, scope}` | `{allowed, reason}` | self | `AUTHORITY_CHECK_PASSED` / `AUTHORITY_CHECK_FAILED` | `AUTHORITY_CHECK_FAILED`, `AUTHZ_CONTEXT_RESOLUTION_FAILED`, `AUTHORITY_STATE_INCONSISTENT` |
| GET | `/authority/audit` | administrator | filters + range | hash-chain rows + integrity manifest | `tenant_admin_authority` | none | none |
| POST | `/authority/audit/export` | administrator | `{range, filters, format}` (electronic-signed) | signed download URL | `tenant_admin_authority` | `AUTHORITY_LOG_EXPORTED` | `EXPORT_FAILED` |

#### 6.3.7 Administrator account management

| Method | Endpoint | Actor | Request | Response | Permission | Audit event | Error codes |
|---|---|---|---|---|---|---|---|
| POST | `/auth/admin/users/:id/unlock` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `ACCOUNT_UNLOCK` | `NOT_LOCKED` |
| POST | `/auth/admin/users/:id/force-password-reset` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `FORCE_PASSWORD_RESET` | `USER_NOT_FOUND` |
| POST | `/auth/admin/users/:id/force-mfa-removal` | administrator | `{reason}` (electronic-signed) | `204` | `tenant_admin_authority` | `MFA_REMOVED_BY_ADMIN` | `USER_NOT_FOUND` |

### 6.4 Workflow engine requirements

#### 6.4.1 Time-bounded resources and timers

| Resource / workflow | Step | Time-to-live or timer | Auto-action | Reminder / notification |
|---|---|---|---|---|
| Multi-factor challenge | created → completed | five minutes | challenge expires; status `expired`; emit `MFA_CHALLENGE_EXPIRED` | none |
| Password reset token | issued → used | fifteen minutes | token expires; user re-requests | none |
| Invitation token | issued → accepted | seven days | token expires; administrator must reissue | T-1 day reminder e-mail |
| Account lockout | locked → auto-unlock | per `lockout_policy.lockout_duration_minutes` | clear `locked_until`; emit `ACCOUNT_UNLOCK` | none |
| Authority Profile assignment | active → expired (when `effective_to` set) | per row's `effective_to` | system identity transitions to `expired`; emit `AUTHORITY_EXPIRED`; increment claims version | T-7 days reminder e-mail to user and tenant administrator |
| Approval delegation | active → expired | per row's mandatory `effective_to` | system identity transitions to `expired`; emit `DELEGATION_EXPIRED`; increment claims version of both users | T-7 days reminder e-mail to both users |
| Session — idle | active → expired | per `session_policies.idle_timeout_minutes` | hook revokes; emit `SESSION_EXPIRED` | front-end warning at T-2 minutes |
| Session — absolute | active → expired | per `session_policies.absolute_timeout_minutes` | hook revokes; emit `SESSION_EXPIRED` | none |
| Refresh token | issued → rotated | per token TTL (default eight hours) | API client refreshes silently | none |
| Refresh-token reuse detection | not applicable | immediate on detection | revoke all sessions of user; emit `TOKEN_REUSE_DETECTED` | security e-mail to user; SOC alert |
| Single-sign-on state token | created → consumed | fifteen minutes | token expires; callback fails with `SSO_STATE_INVALID` | none |
| Password expiry | active → expiring | per `password_policies.max_age_days` | force-password-change flag set on user | T-`expiry_warning_days` reminder e-mail |
| Authority Resolver outage | resolver fails | continuous until resolved | every bootstrap returns 503; persistent banner; SOC alert | continuous SOC alert |

#### 6.4.2 Queue ownership

| Queue | Owner | Purpose |
|---|---|---|
| Authentication-event alerts | Security Operations Centre | Real-time monitoring of `auth_audit_log`. |
| Account lockouts | Tenant administrator | Pending unlocks. |
| Authority change-log review | Platform administrator | Cross-tenant chain-integrity review. |
| Delegations approaching expiry | Tenant administrator | T-7 day rolling window. |
| Pending authority reviews | Tenant administrator | Out-of-band SoD overrides flagged for review. |

#### 6.4.3 Reassignment and delegation

Module 1 workflows are stateless beyond their row state — they have no assignee or work-queue routing in the URS-04 sense. Authority Profile reassignment is performed by revoking the existing assignment (with cascade per BR-01-09) and creating a new assignment to the new holder. Delegation transfers temporary authority from delegator to delegate per §3.4. No automated reassignment is performed by Module 1.

#### 6.4.4 Status locks

An active session whose `claims_version < persisted` is locked from regulated routes via the request-time stale-claims flag. The default policy is Mode A (force revoke at refresh) for regulated authority changes; Mode B is the default at request-time for non-regulated routes; Mode C (request-time deny for regulated routes) is enforced by the authority-check hook.

### 6.5 Business rules

- BR-01-01 — Every successful password mutation revokes all other sessions of the user.
- BR-01-02 — A new password MUST NOT match any of the most recent N hashes per the password policy.
- BR-01-03 — Every new password MUST satisfy the policy.
- BR-01-04 — Login MUST evaluate IP allowlist before password verification.
- BR-01-05 — Login MUST evaluate account lockout before password verification.
- BR-01-06 — On the configured failure threshold, set the lockout-until timestamp and emit the lockout event.
- BR-01-07 — Every issued JSON Web Token MUST carry the claims version; the type-level contract MUST be enforced at build time.
- BR-01-08 — Session claims version is set at creation and never altered.
- BR-01-09 — On refresh, claims-version mismatch combined with a regulated authority revocation OR a base-role downgrade MUST revoke the session and return the dedicated 401 error code (Mode A).
- BR-01-10 — Stale claims at request time MUST either deny regulated routes (Mode C, where enabled) or be tracked for downstream telemetry; a request flag with no consumer is forbidden.
- BR-01-11 — Invitation acceptance MUST NOT auto-assign any Authority Profile.
- BR-01-12 — Single-sign-on callback MUST NOT auto-assign any Authority Profile.
- BR-01-13 — Authority assignment MUST validate against active segregation-of-duties rules.
- BR-01-14 — Delegations MUST carry a non-null effective-to strictly greater than effective-from.
- BR-01-15 — Delegations MUST NOT exceed the delegator's own active scope.
- BR-01-16 — The authority change log MUST be append-only and hash-chained; chain breaks MUST emit `AUTHORITY_STATE_INCONSISTENT`.
- BR-01-17 — The authentication audit log MUST be append-only and hash-chained; audit-log write failure MUST roll back the originating action.
- BR-01-18 — Every user-driven mutation MUST attribute to the authenticated user; the literal `'system'` is forbidden as actor for any user-invoked route.
- BR-01-19 — The front end MUST NOT include `ip`, `userAgent`, `timestamp`, or `performedBy` in any request body; the back end silently drops these and substitutes server-derived values.
- BR-01-20 — Every regulated administrative action MUST be electronically signed through the Controlled Approval Modal.
- BR-01-21 — Every authority change MUST atomically increment the affected user(s)' claims version in the same transaction as the change-log write.
- BR-01-22 — The auto-expiry job MUST run no less frequently than hourly with system attribution and emit the expiry events.

### 6.6 Audit trail requirements

Two append-only hash-chained logs are mandatory. The authentication audit log carries all eighteen authentication events. The authority change log carries all twelve authority events. Both use database advisory locks for serialised writes. Every audit row carries actor identifier, role, server-clock timestamp, action, resource type, resource id, before state, after state, reason where applicable, source IP, user agent, session identifier, correlation identifier, electronic-signature identifier where linked, the previous-row hash, and the row hash. Audit-log write failure rolls back the originating action.

#### Diagram 6.6-A — Audit-log write failure rollback

```mermaid
sequenceDiagram
  autonumber
  participant API as Auth API
  participant DB as Database (transaction)
  participant LOG as Authentication / Authority Audit Log

  API->>DB: BEGIN TRANSACTION
  API->>DB: write business state (for example revoke session)
  API->>LOG: append audit row (with previous_hash + record_hash)
  alt audit write succeeds
    API->>DB: COMMIT
    API-->>API: 2xx response
  else audit write fails
    API->>DB: ROLLBACK
    API-->>API: 500 AUDIT_TRAIL_WRITE_FAILED
    Note over API,DB: business mutation NOT committed.<br/>No state change without audit row.
  end
```

#### 6.6.1 Audit-trail review support endpoints

Periodic audit-trail review obligations and the schedule for review and exception triage are specified in §12.11. The Module 1 substrate MUST expose review-supporting endpoints to make those obligations executable:

- A filterable read endpoint over the authentication audit log and the authority change log (range, tenant, actor, target, event, severity, correlation identifier).
- An integrity-verifier endpoint that recomputes the hash chain across a configured window and returns the start hash, end hash, row count, and validation status.
- An exception-flagging endpoint that allows a reviewer to attach a triage decision (security incident / deviation / CAPA / no-impact) with electronic signature to one or more audit rows; triage decisions are persisted into the authority change log under a dedicated event code so the review trail is itself auditable.
- A scheduled-reminder endpoint that emits review-window reminders to the responsible reviewer and the tenant administrator queue thirty days before each review window opens (per §12.10 / §12.11).

These substrate endpoints are consumed by the URS-22 inspection-readiness workflow and by the URS-30 notification service for review-cycle reminders.

### 6.7 Electronic signature requirements

Every regulated administrative action in this module is electronically signed. The Controlled Approval Modal collects exactly password, meaning of signature, reason for change. The back end derives source IP, user agent, signed-at timestamp, and signed-by identifier from the request context. The signature row is linked to the action row through the electronic-signature identifier.

#### Diagram 6.7-A — Controlled Approval Modal electronic-signature sequence

```mermaid
sequenceDiagram
  autonumber
  participant U as User (administrator)
  participant FE as Frontend
  participant CAM as Controlled Approval Modal
  participant API as Action API
  participant ESIG as Electronic Signatures
  participant ACL as Authority Change Log
  participant DB as Database

  U->>FE: click regulated action button (AuthorityGuard passed)
  FE->>CAM: open modal
  U->>CAM: enter password + meaning + reason
  Note over CAM,API: front end NEVER includes ip / userAgent / timestamp / performedBy
  CAM->>API: POST action body = {password, meaning, reason}
  API->>API: re-authenticate user (password verify)
  alt re-auth fails
    API->>ACL: append ESIG_FAILED
    API-->>CAM: 401 INVALID_CURRENT_PASSWORD
    CAM-->>U: inline error
  else re-auth ok
    alt high-risk action
      API->>API: require multi-factor step-up (TOTP)
    end
    API->>DB: BEGIN TRANSACTION
    API->>ESIG: insert {signed_by, ip, user_agent, signed_at, meaning, reason, content_snapshot}
    ESIG-->>API: electronic_signature_id
    API->>DB: write action target (with electronic_signature_id)
    API->>ACL: append AUTHORITY_* (linked electronic_signature_id)
    API->>DB: COMMIT
    API-->>CAM: 2xx
  end
```

#### 6.7.1 Electronic-signature certification, identity verification, and accountability (21 CFR Part 11 §11.100, §11.200, §11.300)

- Before a user is permitted to execute an electronic signature for any regulated action, the tenant MUST verify the user's identity by an in-person procedure or by a remote identity-proofing process equivalent to a knowledge-based verification with documented evidence.
- The user MUST acknowledge a tenant-issued **electronic-signature policy** stating that electronic signatures executed in Verixa are the legally binding equivalent of handwritten signatures for the regulated workflows of the tenant; the acknowledgement is electronically signed by the user and persisted.
- The system MUST retain three classes of evidence per signature-eligible user: identity-verification evidence (artefact references, verifier identity, date), signature-policy acknowledgement (electronic signature row, timestamp, policy version), and signature activation date (the moment from which the user may execute regulated electronic signatures).
- An electronic signature in Verixa is composed of two distinct identification components per 21 CFR Part 11 §11.200: identification code (the authenticated session identity) and password (entered through the Controlled Approval Modal at the moment of signing). For high-risk actions, multi-factor authentication step-up is additionally required (per §6.7).
- Identification-code and password administrative controls per 21 CFR Part 11 §11.300 are implemented through the password policy (§6.2 `password_policies`), password history, lockout, force-password-change flag, and re-authentication on signature.
- Re-use of an identification-code is forbidden at the platform level; deactivation of a user does not free the identifier for a new individual.
- The certification, identity-verification evidence, and signature-policy acknowledgement records are predicate records under the Part 11 applicability matrix in §14.1 and are retained accordingly.

### 6.8 Record versioning and class-of-change governance

Versioned tables (security policies, single-sign-on configurations, Authority Profiles, scope rules, segregation-of-duties rules) retain all historical versions accessible by version number and effective-from. Soft-delete preserves access to deleted rows from audit-export paths. Hard-delete is reserved for ephemeral or transient rows (multi-factor challenges, single-sign-on state tokens, password reset tokens, expired refresh tokens) and applies only after retention.

---

## 7. Cross-Module Wiring and Change-Impact

### 7.1 Cross-module wiring

#### Diagram 7-A — Module 1 substrate consumed by other modules

```mermaid
graph LR
  subgraph M1 [Module 1 — Authentication, Session & Access]
    AR[Authority Resolver]
    SES[Sessions + claims_version]
    ACL[Authority Change Log]
    AAL[Authentication Audit Log]
    JWT[JWT + claims_version]
    AC[Authority Context]
  end

  subgraph Consumers
    M2[URS-02 RBAC]
    M3[URS-03 Context Gate]
    M4[URS-04 Workflow / HITL / E-Sign]
    M5[URS-05 Authority / Delegation / SoD]
    M6[URS-06 Audit Trail & Data Integrity]
    M8[URS-08 Tenant Master]
    M30[URS-30 Notifications]
    M31[URS-31 Document Quality Gateway]
    M32[URS-32 MIRA AI]
    M35[URS-35 Backup / Restore]
  end

  AC --> M2
  AC --> M3
  AC --> M4
  AC --> M5
  AC --> M32
  AAL --> M6
  ACL --> M6
  ACL --> M5
  SES --> M3
  JWT --> M2
  M5 --> ACL
  M5 --> AR
  M8 --> SES
  M1 -.notifies.-> M30
  M35 -.preserves chain.-> ACL
  M35 -.preserves chain.-> AAL
  M31 -.consumes electronic_signature_id.-> ACL
```

### 7.2 Change-Impact Matrix

This matrix is the regulated change-governance artefact for Module 1. Any proposed change MUST pass through this matrix during impact assessment under URS-13 before approval.

| # | Module 1 artefact | Class | Affected modules | Specific impact | Required action | Re-validation scope |
|---|---|---|---|---|---|---|
| CIM-01 | Authority Context shape | 1 | URS-02, URS-03, URS-04, URS-05, URS-31, URS-32, every module with `<AuthorityGuard>` | Front-end guards dereference fields; back-end hooks parse unknown shape; MIRA envelope echoes stale shape; e-sign cannot link decision to authority of record | Update shared schemas, front-end guards and stores, every back-end handler reading the context, MIRA envelope, audit-replay tooling | Full IQ on shared types + OQ regression on every consuming module + PQ on at least one regulated-action E2E per consumer |
| CIM-02 | JWT payload (claims version semantics) | 1 | URS-02, URS-04, URS-05, URS-06, URS-32, URS-35 | Authenticate hook claims-version compare misfires; refresh-time critical-change detection skipped; audit replay cannot reconstruct authority of record | Update shared types; rotate signing secret if claim semantics change; backfill or migrate existing tokens | OQ for authenticate / refresh / bootstrap; PQ for J-11, J-12 |
| CIM-03 | Session row schema | 1 | URS-03, URS-06, URS-30 | Context gate fails closed if expected column missing; audit attribution loses session correlation; notifications miss session-revoke triggers | Schema migration with idempotency guards; update consumers | IQ on migration; OQ on context filter; PQ on session-revoke and hijack journeys |
| CIM-04 | Authority Profile catalogue (add or deprecate a key) | 3 (add) / 1 (deprecation) | All modules gating buttons by that key | Buttons gated by deprecated key permanently disabled; new key has no consumers until opt-in | For deprecation: bulk-revoke assignments and delegations, update guard props, update segregation-of-duties rules, emit revoke events. For addition: assign and seed catalogue row | OQ on catalogue migration; PQ on every consumer's regulated-action E2E that referenced the key |
| CIM-05 | Scope dimensions | 1 | URS-05, URS-03, URS-07/09/10/11/28, URS-31, every assigning module | Resolver may grant or deny incorrectly; scope match no longer covers the new dimension | Update resolver, scope-rule registry, assignment / delegation forms, segregation-of-duties engine | IQ on schema; OQ on resolver matrix tests; PQ on at least one assign / delegate / approve E2E per dimension |
| CIM-06 | Authority change-log event vocabulary | 3 (add) / 1 (rename) | URS-05, URS-06, URS-30, URS-22, URS-35 | Audit replay incomplete; lifecycle reports miss events; notification rules silent | Update writer call sites; update audit-replay tooling; update notification rules; vocabulary completeness gate | OQ on writer presence; PQ on chain-integrity export |
| CIM-07 | Authentication audit-log event vocabulary | 3 (add) / 1 (rename) | URS-06, URS-30, URS-22, URS-35 | As CIM-06 for authentication events | Update writers; update SOC alerts; update inspection-prep export | OQ + PQ |
| CIM-08 | Authority Resolver decision algorithm | 2 | URS-04, URS-05, every regulated-action consumer | Decisions today as DENY become ALLOW (or vice versa) without contract change. **Highest inspector exposure.** | Document the change with risk assessment; run differential testing of resolver decisions; obtain QA, RA, security approval before deployment | Full OQ regression on resolver test pack; PQ on every Class-A regulated journey across the platform; differential analysis report archived |
| CIM-09 | Mode A / B / C policy | 2 | URS-02, URS-04, URS-18, URS-23 | Tighter or looser stale-claims handling | Document policy change; update authority-check hook; align user experience | OQ on hook; PQ on stale-claims scenarios for QP release, batch disposition, deviation closure, CAPA closure |
| CIM-10 | Cookie semantics (HttpOnly, Secure, SameSite, refresh path, max-age) | 1 | All authenticated modules; mobile and embedded clients | Cross-subdomain single-sign-on breaks; mobile webview behaviour changes; Cross-Site Request Forgery posture shifts | Update API client and bootstrap docs; coordinate with platform | Penetration scan; OQ on session lifecycle; PQ on single-sign-on callback; mobile compatibility regression |
| CIM-11 | Refresh-token rotation policy | 2 | URS-04 (long-running approvals), URS-32 (long-poll), URS-35 (DR sessions across restore) | UX shifts; reuse-detection false-positive rate changes | Update API client interceptor; document operational expectations | OQ + PQ on J-11; soak test for twenty-four-hour active sessions |
| CIM-12 | Three-layer guard contract | 1 | Every front-end module containing a regulated action | Guard prop or behaviour change forces every regulated button retouch | Update guard components; update consumer JSX; static-analysis gate confirming nesting order is preserved | OQ on guard components; PQ on at least one regulated action per consumer |
| CIM-13 | Controlled Approval Modal contract | 1 | URS-04, URS-12, URS-13, URS-18, URS-23, URS-24, URS-26, URS-28, URS-33, URS-34 | Adding required field invalidates every existing call site; removing field weakens 21 CFR Part 11 compliance | Update modal API; align all call sites; align electronic-signatures write contract | Full OQ on modal; PQ on every regulated action that uses it; e-sign integrity penetration test |
| CIM-14 | Electronic-signature server-derivation contract | 1 | URS-04, URS-26, URS-28, every regulated-action handler | Regression to client-supplied fields breaks ALCOA+ Attributable and Original | Static-analysis gate forbidding client-supplied attribution; audit of every handler | Static gate + OQ + Penetration |
| CIM-15 | Cross-Site Request Forgery regeneration policy | 1 | All authenticated modules | Stale token causes 403; missed regeneration causes session-pinned token reuse | Update API client interceptor; update consumers' error handling | OQ on bootstrap; PQ on cross-tab refresh; penetration test for token reuse |
| CIM-16 | Claims-version increment trigger | 2 | URS-04, URS-05, URS-06 | Atomicity break (audit row written but counter not incremented, or vice versa) misfires J-11 / J-12 cascades | Wrap every authority change in a single transaction; integration test for partial failure | OQ + PQ; concurrency test; chaos test for partial commit |
| CIM-17 | Auto-expiry job behaviour | 2 | URS-05, URS-06, URS-30 | Lower frequency lets expired authorities linger; attribution change loses named system actor | Update job spec; document service-level agreement (≤ sixty minutes after effective-to); align operational dashboards | OQ on job; PQ on expiry journeys |
| CIM-18 | Hash-chain integrity verifier | 1 | URS-06, URS-22, URS-35 | Restore that breaks the chain corrupts regulatory evidence | Update verifier; coordinate with restore tooling; documented disaster-recovery drill | IQ on chain; PQ for DR drill; archived integrity manifest with every export |
| CIM-19 | Tenant-isolation contract on Module 1 tables | 1 | All authenticated modules; especially URS-08 platform-context flows | Row-Level Security regression is cross-tenant data exposure; Tenant Data Access Layer signature change breaks every consumer | Static analysis + migration test; coordinate with every consumer | Full OQ + Penetration + cross-tenant replay test |
| CIM-20 | Authority API endpoint paths or response shapes | 1 | URS-05, URS-06, front-end administrator pages, MIRA envelope | Endpoint rename or shape change breaks every administrator UI and resolver consumer | Update API contract; align consumers; deprecation window where possible | OQ on API contract tests; PQ on administrator UI lifecycle |
| CIM-21 | Single-sign-on configuration model | 2 | URS-08 (tenant onboarding), URS-30 (single-sign-on failure alerts), URS-32 (if single-sign-on bound) | Just-in-time provisioning rule changes can grant or starve role or authority on first login | Update single-sign-on service; update tenant-onboarding playbook; align audit | OQ + PQ for J-07; tenant-onboarding regression |
| CIM-22 | Password / lockout / IP allowlist / session policy schemas | 2 (schema) / 4 (configuration values) | URS-08, URS-30 | Schema change breaks consumer admin UI; value change is operational only | Versioned policy migration; admin UI alignment for schema; operational comms for values | OQ on policy CRUD; PQ on policy-driven enforcement |
| CIM-23 | Multi-factor enrolment surface | 2 | URS-30, URS-31, URS-08 | Disabling backup codes raises lockout risk | Update enrolment and verification flows; align tenant-policy admin | OQ + PQ for J-08 |
| CIM-24 | Notification triggers from Module 1 events | 3 | URS-30 | Adding a trigger creates new volume; removing one masks a security event | Update notification rules; align retention | OQ on URS-30 rule registry; PQ on critical paths |
| CIM-25 | Reports list (filters, columns, retention) | 3 / 4 | URS-22 (inspection prep export), URS-06 | Inspection prep may rely on a column; removing it breaks export | Coordinate with URS-22 and URS-06; deprecation window | OQ on report queries; PQ on inspection export |

### 7.3 Change classification and re-validation triggers

| Class | Definition | Examples | Required gates | Default re-validation |
|---|---|---|---|---|
| 1 — Substrate-breaking | Schema, contract, or semantic change that can break consumers without code change in those consumers | CIM-01, 02, 03, 05, 10, 12, 13, 14, 15, 18, 19, 20 | URS-13 approval by QA, RA, Security, Platform; routed through DQG; founder electronic signature when authority semantics are touched | Full IQ on schema + OQ regression on Module 1 + OQ regression on every consuming module + PQ on at least one regulated journey per consumer |
| 2 — Semantic-shift | Behaviour change without contract change | CIM-08, 09, 11, 16, 17, 21, 23 (schema-side), 22 | URS-13 approval by QA, RA, Security; differential test report archived | OQ regression scoped; PQ on regulated journeys impacted |
| 3 — Additive | Pure addition not changing any existing consumer's contract | CIM-04 (add), CIM-06 (add), CIM-07 (add), CIM-24, CIM-25 | URS-13 approval by QA + RA; vocabulary completeness gate | OQ on the new artefact; PQ when a consumer opts in |
| 4 — Configuration | Tenant-level or operational value change with no schema or code change | Lockout thresholds, password-policy values, session timeouts, IP allowlist entries | Tenant-administrator electronic signature | None for Module 1; operational acknowledgement only |

Class 1 changes MUST be packaged with a written impact assessment using §7.2, a deprecation or sunset window of at least thirty calendar days where backward compatibility is feasible, an updated traceability matrix, and an updated regression pack. The Change-Impact Matrix itself is a controlled artefact; any addition or modification to §7.2 follows §7.3.

---

## 8. AI / Automation / Human-in-the-Loop Controls

Module 1 contains no AI. The Authority Resolver is deterministic. The account-lockout engine is rule-based. The IP allowlist engine is a CIDR match. The refresh-token reuse detection is deterministic. The session-fingerprint check is deterministic. No large-language model is invoked anywhere on the authentication or authorisation path.

The applicability assessment under EU AI Act (Regulation (EU) 2024/1689) Article 3(1) yields: not applicable to this module. No AI system is in scope. The applicability assessment is documented for the technical-documentation pack so an inspector observes the explicit exclusion.

The MIRA AI agent (URS-32) does not advise on authentication, authorisation, or session decisions. The MIRA prompt envelope echoes the Authority Context for downstream regulated-task gating only; it never alters authentication state.

The human-in-the-loop pattern in this module covers every administrative authority change (assign, revoke, delegate, expire-by-policy override). Every such action routes through the Controlled Approval Modal and electronic signature.

---

## 9. Reports, Dashboards, and Exports

| Report | Filters | Columns | Access | Format | Audit | Retention |
|---|---|---|---|---|---|---|
| Authentication events (operational) | range, tenant, user, event | event, actor, IP, user agent, session, correlation | administrator | comma-separated values, PDF, JSON-lines | yes | seven years |
| Authority change log | range, tenant, actor, target, action | full row + chain integrity badge | administrator | comma-separated values, PDF, JSON-lines | yes | twenty-five years |
| Active sessions | tenant, user, since | user, IP, user agent, last active, expires | administrator | comma-separated values | yes | ninety days |
| Failed login attempts | range, tenant, IP | user, IP, count, last failure | administrator | comma-separated values | yes | one year |
| Multi-factor enrolment status | tenant | user, enrolled, method, enrolled at | administrator | comma-separated values | yes | duration of role |
| Password expiry | tenant | user, last change, days to expiry | administrator | comma-separated values | yes | duration of role |
| Account lockouts | range, tenant | user, locked-until, reason | administrator | comma-separated values | yes | one year |
| Single-sign-on usage | range, tenant, provider | user, provider, success, latency | administrator | comma-separated values | yes | one year |
| Authority Profile coverage | tenant, profile | user, scope, effective-from, effective-to | administrator | comma-separated values | yes | seven years |
| Delegation register | tenant, status, range | from, to, profile, scope, effective-from, effective-to | administrator | comma-separated values | yes | seven years |
| Hash-chain integrity report | range | start hash, end hash, row count, integrity status | administrator | PDF | yes | twenty-five years |

Every export is electronically signed. Download URLs are signed and time-to-live limited to fifteen minutes.

---

## 10. Notifications and Queues

| Trigger | Channel | Recipient | Priority | Retry | Suppression | Audit |
|---|---|---|---|---|---|---|
| Password reset requested | e-mail | self | normal | three with backoff | one per minute per e-mail | yes |
| Password change | e-mail | self | normal | three | one per minute per user | yes |
| Account lockout | e-mail | self | high | three | one per fifteen minutes per user | yes |
| Session hijack detected | e-mail and chat to security operations centre | self and SOC | critical | five | one per five minutes per user | yes |
| Authority assigned (regulated) | e-mail | target | normal | three | none | yes |
| Authority revoked (regulated) | e-mail | target | high | three | none | yes |
| Delegation created | e-mail | both parties | normal | three | none | yes |
| Delegation revoked | e-mail | both parties | high | three | none | yes |
| Delegation expiry warning (T minus seven days) | e-mail | both parties | normal | three | one per day per delegation | yes |
| Password expiry warning | e-mail | self | normal | three | one per day per user | yes |
| Invitation issued | e-mail | invitee | normal | three | one per fifteen minutes per e-mail | yes |
| Single-sign-on callback failure | e-mail and chat to security operations centre | administrator | high | three | one per five minutes per tenant | yes |
| Authority context resolution failed | chat to security operations centre | SOC | critical | continuous until resolved | one per minute per tenant | yes |

Queues: own-sessions list (self), own-delegations list (self), pending authority reviews (administrator), account-lockouts queue (administrator), delegations approaching expiry (administrator), authority-audit queue (platform administrator). No AI suggestion queue exists in this module.

---

## 11. Error Handling and Negative Paths

### 11.1 Error envelope

All error responses follow the envelope: human message, machine code in upper-snake-case, optional structured details, correlation identifier.

### 11.2 Authentication-related error codes

| Code | HTTP | Path | User interface behaviour |
|---|---|---|---|
| INVALID_CREDENTIALS | 401 | login | "Incorrect email or password." (generic) |
| ACCOUNT_DEACTIVATED | 403 | login | "Your account has been deactivated. Contact your administrator." |
| ACCOUNT_LOCKED | 423 | login | locked-state UI with countdown |
| PASSWORD_EXPIRED | 403 | login | redirect to change-password with flash |
| MFA_REQUIRED | 200 | login | navigate to multi-factor challenge; not an error |
| MFA_INVALID_CODE | 401 | multi-factor | "Invalid code. Please try again." (preserve challenge) |
| MFA_CHALLENGE_EXPIRED | 401 | multi-factor | "Your login session has expired. Please start again." (redirect to login) |
| MFA_ATTEMPTS_EXCEEDED | 423 | multi-factor | "Too many invalid codes. Please log in again." |
| IP_NOT_ALLOWED | 403 | login | "Access is not permitted from your current network." |
| SESSION_EXPIRED | 401 | any | clear auth, redirect to login (return-to) |
| SESSION_REVOKED | 401 | any | clear auth, redirect to login |
| SESSION_HIJACK_DETECTED | 401 | any | clear auth, redirect to login (security message) |
| TOKEN_REUSE_DETECTED | 401 | refresh | clear auth, redirect to login (security message) |
| TOKEN_EXPIRED | 401 | any | silent refresh; on failure clear and redirect |
| CLAIMS_VERSION_MISMATCH | 401 | refresh / regulated route | clear auth, redirect to login ("Your permissions have changed. Please log in again.") |
| SESSION_REVOKED_AUTHORITY_CHANGE | 401 | refresh | clear auth, redirect to login ("Your session was terminated because your authority was updated.") |
| AUTHZ_CONTEXT_RESOLUTION_FAILED | 503 | login / refresh / bootstrap | user remains logged in; persistent banner; AuthorityGuard disables |
| AUTHORITY_CHECK_FAILED | 403 | regulated route | "You do not have the required authority to perform this action." |
| DELEGATION_INVALID | 403 | regulated route or delegation | "The delegation you are relying on has expired or been revoked. Refresh to update." |
| AUTHORITY_STATE_INCONSISTENT | 500 | any authority operation | generic toast with correlation identifier; SOC alerts |
| SOD_VIOLATION | 403 | authority assign or delegate | "This violates a Segregation-of-Duties rule." (with rule identifier) |
| CSRF_INVALID | 403 | any mutation | force bootstrap to recover token; do not auto-retry |
| AUDIT_TRAIL_WRITE_FAILED | 500 | any state-changing action | generic error; the action did NOT commit |
| INVITE_TOKEN_INVALID | 400 | accept invitation | "Your invitation is no longer valid. Contact your administrator." |
| RESET_TOKEN_INVALID | 400 | reset password | "This link is no longer valid. Please request a new one." |
| PASSWORD_POLICY_VIOLATION | 400 | change / reset / invitation | inline list of failed policy rules |
| PASSWORD_HISTORY_REUSED | 400 | change / reset / invitation | "You cannot reuse a recent password." |
| INVALID_CURRENT_PASSWORD | 400 | change password | inline error |
| SSO_STATE_INVALID | 400 | single-sign-on callback | redirect to login with flash |
| SSO_PROVIDER_ERROR | 500 | single-sign-on callback | redirect to login with flash and correlation identifier |
| TENANT_INACTIVE | 403 | login / refresh | "This tenant is currently inactive." |

### 11.3 Negative-path catalogue

| Scenario | Detection point | Response | User-interface behaviour |
|---|---|---|---|
| Validation error (Zod schema) | Front end and back end (re-validation) | HTTP 400 with field-level detail | inline error per field; submit re-enabled after fix |
| Permission denied (Role-Based Access Control) | RBAC hook | HTTP 403 with code | render `<AccessDenied />` without API call from `<PermissionGuard>`; if back-end-detected, generic toast |
| Authority denied (Authority-check hook) | authority-check hook | HTTP 403 `AUTHORITY_CHECK_FAILED` | non-redirecting toast; the `<AuthorityGuard>` already disabled the button — back-end denial is defense in depth |
| Missing master data (referenced site / product / study deleted) | Authority Resolver | HTTP 503 `AUTHZ_CONTEXT_RESOLUTION_FAILED` | persistent banner; AuthorityGuard buttons disabled |
| Duplicate uniqueness violation | database | HTTP 409 with the descriptive code (for example `PROFILE_KEY_DUPLICATE`) | inline error |
| Stale version conflict (concurrent administrator policy edit) | database optimistic version | HTTP 409 `STALE_VERSION` | toast prompts the caller to refetch and re-apply |
| Failed upload | not applicable in Module 1 | not applicable | not applicable |
| Failed electronic signature | electronic-signature service | HTTP 422 `ESIG_FAILED`; transaction rolled back | inline error in modal |
| Failed integration (notification delivery) | notification service | non-blocking; queued retry per URS-30 | not surfaced unless escalated |
| Failed notification (after retries exhausted) | notification service | logged and surfaced to administrator queue; does not block originating action | administrator dashboard alert |
| Failed export | export service | HTTP 500 `EXPORT_FAILED` | toast with correlation identifier; retry available |
| AI unavailable | not applicable in Module 1 | not applicable | not applicable |
| Workflow-engine failure | URS-04 owns; bubbles up here only on regulated authority transitions | HTTP 500 with correlation identifier | toast; SOC alert |
| Audit-log write failure (any) | audit service | HTTP 500 `AUDIT_TRAIL_WRITE_FAILED`; transaction rolled back | toast; the originating action did NOT commit |
| Authority Resolver outage | Authority Resolver | HTTP 503 `AUTHZ_CONTEXT_RESOLUTION_FAILED` | persistent banner; AuthorityGuard buttons disabled; SOC alert |
| Hash-chain integrity break | chain verifier | HTTP 500 `AUTHORITY_STATE_INCONSISTENT` | administrator dashboard alert; SOC alert; export blocked until investigated |
| Single-sign-on state token expired | callback | HTTP 400 `SSO_STATE_INVALID` | redirect to login with flash |
| Single-sign-on provider error (identity provider down) | callback | HTTP 500 `SSO_PROVIDER_ERROR` | redirect to login with flash + correlation identifier |
| Tenant inactive at login | login | HTTP 403 `TENANT_INACTIVE` | "This tenant is currently inactive." |
| Refresh-token reuse | refresh hook | HTTP 401 `TOKEN_REUSE_DETECTED`; revoke all sessions of user | redirect to login with security message; security e-mail to user; SOC alert |
| Cross-Site Request Forgery token stale | CSRF hook | HTTP 403 `CSRF_INVALID` | toast prompts user to refresh; UI silently calls bootstrap to recover token; **never auto-retry** |
| Multi-factor challenge expired | multi-factor service | HTTP 401 `MFA_CHALLENGE_EXPIRED` | redirect to login with flash |
| Multi-factor challenge attempts exhausted | multi-factor service | HTTP 423 `MFA_ATTEMPTS_EXCEEDED` | redirect to login with flash |
| Account locked (login attempt) | lockout hook | HTTP 423 `ACCOUNT_LOCKED` with `lockedUntil` | locked-state UI with countdown |
| Password policy violation | policy validator | HTTP 400 `PASSWORD_POLICY_VIOLATION` | inline list of failed rules |
| Password history reuse | history validator | HTTP 400 `PASSWORD_HISTORY_REUSED` | inline error |
| Session hijack detected (fingerprint mismatch) | authenticate hook | HTTP 401 `SESSION_HIJACK_DETECTED`; session revoked | redirect to login with security message; security e-mail to user; SOC alert |
| Idle timeout reached | authenticate hook | HTTP 401 `SESSION_EXPIRED` | redirect to login |
| Absolute timeout reached | authenticate hook | HTTP 401 `SESSION_EXPIRED` | redirect to login |
| IP not in allowlist | login pre-check | HTTP 403 `IP_NOT_ALLOWED` | "Access is not permitted from your current network." |
| Self-modification attempted (administrator changing own role / authority) | authority service | HTTP 403 `SELF_MODIFICATION_FORBIDDEN` | inline error in modal |
| Segregation-of-Duties violation on assignment | SoD engine | HTTP 403 `SOD_VIOLATION` with rule identifier in details | inline error in modal naming the violated rule |

---

## 12. Security, Privacy, and Tenant Isolation

### 12.1 Authentication controls

- Passwords are hashed with Argon2id using a Key-Management-Service-managed pepper.
- Multi-factor authentication is via Time-based One-Time Password (six-digit, thirty-second window). Short-Message-Service second factor is prohibited.
- Backup codes are generated once on enrolment, encrypted at rest, displayed once to the user, and never retrievable again.
- Single sign-on supports OpenID Connect and Security Assertion Markup Language with state and nonce verification on callback.

### 12.2 Session and token controls

- Access JSON Web Token: signed with a key managed by the Key Management Service; carries `userId`, `tenantId`, `role`, `email`, `sessionId`, `claimsVersion`; eight-hour maximum lifetime; carried only in `verixa_access` cookie (HttpOnly, Secure in production, `SameSite=Lax`).
- Refresh token: hashed at rest; rotated on every use; reuse triggers full-user session revocation; carried only in `verixa_refresh` cookie scoped to the refresh endpoint path.
- Session row carries `claims_version` set at creation and never altered after.
- Session fingerprint: source IP /24 prefix (IPv4) or /64 prefix (IPv6) plus normalised user agent; mismatch triggers session revocation.
- Idle and absolute timeouts are tenant-configurable in the session policy.

### 12.3 Cross-Site Request Forgery protection

- Double-submit token + `X-CSRF-Token` request header.
- Token regenerated on the bootstrap endpoint.
- Stale token returns HTTP 403 `CSRF_INVALID`; the user interface forces a bootstrap call to recover; auto-retry is forbidden.

### 12.4 Authorisation pipeline

- Front end: three-layer guard hierarchy `<RoleGuard>` → `<PermissionGuard>` → `<AuthorityGuard>`.
- Back end: authenticate hook → tenant hook → Role-Based Access Control hook → Context Gate hook → workflow hook → authority-check hook. Each hook fails closed.

### 12.5 Tenant isolation

- Every database operation routes through the Tenant Data Access Layer with tenant context bound to the connection.
- Every Module 1 table has Row-Level Security enabled in the same migration that creates it; the policy is `tenant_id = current_setting('app.current_tenant_id')::uuid`.
- Cross-tenant operations route through the explicit platform-context API, available only to `platform_admin` and `super_admin`.

### 12.6 Encryption

- At rest: all secrets (multi-factor secret, refresh-token hash, single-sign-on client secret, password hash) encrypted under cloud Key Management Service keys; key rotation at least annually.
- In transit: TLS 1.2 or higher; HTTP Strict Transport Security preload; ciphers per current OWASP guidance.
- Database backups are encrypted; restore preserves Row-Level Security and hash-chain integrity per URS-35.

### 12.7 Logging hygiene

- Structured logs with correlation identifier on every request.
- Logs scrub passwords, tokens, multi-factor secrets, single-sign-on secrets, and any field tagged sensitive.
- Log retention is one year for operational logs; audit logs are retained per their dedicated retention rules (§6.2).

### 12.8 Privacy and data residency

- Personal data minimised; users have the right to access (export own session list, own audit events) and the right to deactivation (soft-delete via tenant administrator).
- Data residency is tenant-configurable; defaults to the cloud region of the tenant's primary site per URS-35.
- The launch URS does not yet enumerate tenant-jurisdiction-specific privacy obligations (GDPR, DPDP Act, HIPAA, CCPA); each is acknowledged in §14 and implemented per the tenant's contractual jurisdiction.

### 12.9 Secure export

- Every audit-log export is electronically signed.
- Download URLs are signed and time-to-live limited to fifteen minutes.
- Exports include a self-verifying integrity manifest.

### 12.10 Periodic access review

- All active users, base-role memberships, Authority Profiles, delegations, platform identities, system identities, break-glass rights, and external identities (per §3.2.3) MUST be reviewed at least quarterly for tenants operating Good Manufacturing Practice / Good Clinical Practice / Good Laboratory Practice activities ("GxP-critical tenants") and at least semi-annually for non-critical tenants.
- The review MUST be performed by a manager independent of the day-to-day operation of the access being reviewed, or by a Quality Assurance delegate with `tenant_admin_authority`.
- The review MUST cover: continued business need for each Authority Profile assignment; expiry-date appropriateness; scope correctness; segregation-of-duties posture against any new role combinations; orphaned accounts (deactivated users still holding active authority); break-glass `global_quality_oversight` use during the period and rationale.
- The review outcome MUST be documented and electronically signed by the reviewer; the signed review record MUST be retained for the same period as the authority change log (twenty-five years).
- Unresolved access exceptions identified by the review MUST create either a CAPA (URS-18) or a security deviation (URS-16) within five business days of the review.
- The review schedule MUST be configurable per tenant in the security policy and MUST emit calendar reminders to the responsible reviewer and to the tenant administrator queue thirty days before the review window opens.

### 12.11 Periodic audit-trail review

- The authentication audit log and the authority change log MUST be reviewed against a documented risk-based schedule.
- High-risk events — `SESSION_HIJACK_DETECTED`, `TOKEN_REUSE_DETECTED`, `AUTHZ_CONTEXT_RESOLUTION_FAILED`, `AUTHORITY_STATE_INCONSISTENT`, `AUDIT_TRAIL_WRITE_FAILED`, `ACCOUNT_LOCKOUT` for `tenant_admin` and platform identities, every use of `global_quality_oversight` be reviewed within one business day of the event.
- Routine audit-trail review MUST be documented at least monthly for production tenants and at least quarterly for non-production tenants.
- Audit-trail review exceptions MUST be triaged within one business day as one of: security incident (route to URS-35 incident response), deviation (URS-16), CAPA (URS-18), or no-impact with documented rationale and reviewer signature.
- Reviewer attribution, review date, scope of review, exceptions identified, and triage decisions MUST be persisted as a controlled record electronically signed by the reviewer and retained for the same period as the underlying audit log.

---

## 13. Data Integrity and ALCOA+ Controls

| Principle | Module 1 control | Requirement | Verification |
|---|---|---|---|
| Attributable | Every audit and authority row carries actor user identifier and tenant identifier; the literal `'system'` is forbidden as actor for user-invoked routes (BR-01-18, BR-01-19). | URS-01-AUD-001 | Integration test: every state mutation produces an audit row with non-null actor identifier. |
| Legible | Audit rows store structured JSON metadata; exports render in human-readable PDF and machine-readable comma-separated values and JSON-lines. | URS-01-REP-001 | End-to-end export test: PDF readable; comma-separated values import without ambiguity. |
| Contemporaneous | All timestamps from server clock; client-supplied timestamps dropped (BR-01-19). | URS-01-AUD-002 | Integration test: client-supplied `signed_at` or `timestamp` in payload does not overwrite server timestamp. |
| Original | Hash-chained logs; soft-delete; versioned policies; signature snapshots (BR-01-16, §6.8). | URS-01-AUD-003 | Validation test: chain integrity verifier never breaks across migrations. |
| Accurate | Zod validation at every boundary; back-end re-validation; unique constraints; segregation-of-duties checks (BR-01-13). | URS-01-DATA-001 | Integration test: malformed inputs rejected at both boundaries. |
| Complete | Every event in the thirty-code vocabulary has at least one writer; auto-expiry covers expiry events (BR-01-22). | URS-01-AUD-004 | Validation test: vocabulary completeness — every code emitted in the regression suite. |
| Consistent | Hash-chain ordering enforced by advisory lock; claims version strictly monotonic per (user, tenant). | URS-01-AUD-005 | Concurrency test: parallel increments produce a strictly increasing sequence. |
| Enduring | Retention policies (seven years authentication, twenty-five years authority); cold-archive per URS-35. | URS-01-DATA-002 | Migration test: archive and restore preserve chain integrity. |
| Available | Audit-log read paths administrator-accessible; export self-service; service-level agreement per URS-35. | URS-01-REP-002 | End-to-end test: administrator can read a row written twenty-four hours ago within the service-level agreement. |

---

## 14. Regulatory Mapping

| Identifier | Control | Regulation | Clause | Applicable | Implementation expectation |
|---|---|---|---|---|---|
| RG-01-001 | Limit access to authorised individuals | 21 CFR Part 11 | §11.10(d) | Yes | Role-based access control + `<RoleGuard>` + per-route permission check + Row-Level Security |
| RG-01-002 | Authority checks for system functions | 21 CFR Part 11 | §11.10(g) | Yes | Authority Resolver + authority-check hook + `<AuthorityGuard>` |
| RG-01-003 | Audit trail of operator actions | 21 CFR Part 11 | §11.10(e) | Yes | Hash-chained authentication audit log and authority change log |
| RG-01-004 | Identity and components of electronic signature | 21 CFR Part 11 | §11.100, §11.200 | Yes | Re-authentication + meaning + reason; server-derived metadata |
| RG-01-005 | Electronic-signature linking | 21 CFR Part 11 | §11.70 | Yes | Electronic-signature identifier linked into action row |
| RG-01-006 | Password integrity / system-administrator authority | 21 CFR Part 11 | §11.300 | Yes | Password policy, history, expiry, lockout |
| RG-01-007 | Validation of computerised systems | EU GMP Annex 11 | §4 | Yes | CSV / CSA pack per §17 |
| RG-01-008 | Audit trail | EU GMP Annex 11 | §9 | Yes | as RG-01-003 |
| RG-01-009 | Logical access controls | EU GMP Annex 11 | §12, §12.1 | Yes | Role-based access control + Authority + tenant isolation + Row-Level Security |
| RG-01-010 | Electronic-signature controls | EU GMP Annex 11 | §14 | Yes | Controlled Approval Modal |
| RG-01-011 | Incident management and business continuity | EU GMP Annex 11 | §13, §16 | Yes | Resolver-failure 503; SOC alerts; URS-35 business continuity plan |
| RG-01-012 | Documentation and record integrity | EU GMP Chapter 4 | applicable | Yes | Versioning + retention + ALCOA+ |
| RG-01-013 | Risk-based assurance | FDA Computer Software Assurance for Production and Quality Management System Software, Final Guidance, February 2026 (supersedes the September 2025 final guidance) | applicable | Yes | Risk classification documented per the validation pack |
| RG-01-014 | ALCOA+ data integrity | MHRA Data Integrity Guidance (2018) | nine principles | Yes | §13 mapping |
| RG-01-015 | Records retention | EU GMP Annex 11 | §17 | Yes | Seven years authentication; twenty-five years authority; cold archive |
| RG-01-016 | Privacy and data-subject rights | GDPR; DPDP Act (India) | applicable | Conditional (per data residency) | Soft-delete; export-own-data |
| RG-01-017 | Identity-management standards | ISO/IEC 27001 | A.5.16, A.8.5 | Yes | Password policy + multi-factor authentication + access review |
| RG-01-018 | EU AI Act applicability | Regulation (EU) 2024/1689 | Article 3(1) | Not applicable to this module | No AI; documented exclusion |
| RG-01-019 | India regulatory framework (CDSCO; D&C Act 1940; Medical Devices Rules 2017; New Drugs and Clinical Trials Rules 2019; CDSCO GCP) | Per applicability | applicable per tenant operation | Conditional | Jurisdictional documentation; QA, RA, legal confirmation per tenant |
| RG-01-020 | Notifications integrity | Internal | not applicable | Yes | URS-30 substrate |

### 14.1 Predicate-rule applicability matrix (Part 11 scope)

21 CFR Part 11 applies only to records and signatures that satisfy a **predicate rule** (a Good Manufacturing Practice / Good Clinical Practice / Good Laboratory Practice / pharmaceutical-quality requirement that mandates retention of the record). The table below documents Module 1's position on each record class so that Part 11 applicability is defensible during inspection.

| Record / signature | Predicate-rule basis | Part 11 applicable? | Retention | Owner | Evidence |
|---|---|---|---|---|---|
| Electronic signature for authority assignment, revocation, delegation | GxP approval / controlled access (21 CFR Part 211, ICH Q10, EU GMP Chapter 4 documentation) | Yes | seven years (or longer if the linked downstream record requires) | Quality Assurance / Validation | Electronic-signature row + linked authority-change-log row + audit export |
| Authority change log | Access-control and approval evidence (21 CFR Part 11 §11.10(d), §11.10(e); EU GMP Annex 11 §9 and §12) | Yes | twenty-five years | Quality Assurance / Information Security | Hash-chain integrity verifier output + signed export manifest |
| Authentication audit log | Access-control evidence (21 CFR Part 11 §11.10(d), §11.10(e); EU GMP Annex 11 §9 and §12) | Yes | seven years | Information Security / Quality Assurance | Audit export + chain integrity manifest |
| Electronic signature for password change, multi-factor enrolment removal, security-policy edit | Access-control administrative event (21 CFR Part 11 §11.10(g), §11.300) | Yes | seven years | Information Security / Quality Assurance | Electronic-signature row + audit row |
| Session row (login event) | Security evidence; not a predicate record by itself | Conditional — Part 11 applies to the audit row that captures session creation; the session row itself is operational | ninety days post-expiry unless an investigation hold extends retention | Information Security | Session retention rule + audit export |
| Refresh token (hashed) | Operational security artefact | No | ninety days post-revocation | Information Security | Token lifecycle test |
| Multi-factor challenge row | Transient security artefact | No (the audit row of the multi-factor event IS predicate evidence; the challenge row itself is operational) | twenty-four hours | Information Security | Challenge lifecycle test |
| Password reset token | Transient security artefact | No / supporting evidence only | twenty-four hours | Information Security | Token lifecycle test |
| Single-sign-on state token | Transient security artefact | No | fifteen minutes | Information Security | State-token lifecycle test |
| Password history hash | Compliance enforcement evidence (21 CFR Part 11 §11.300(b)) | Yes | per password policy `historyCount`; minimum eighteen months | Information Security | Password-policy enforcement test |
| Account lockout row | Security evidence (21 CFR Part 11 §11.300(d)) | Yes (operational record evidencing access control) | ninety days post-clear; permanent attribution remains in the audit log | Information Security | Lockout retention rule + audit export |
| IP allowlist (versioned) | Access-control configuration evidence (EU GMP Annex 11 §12) | Yes | retain history (versioned) | Information Security / QA | Version history + administrator electronic signatures |
| Session policy / lockout policy / password policy / multi-factor policy (versioned) | Configuration baseline evidence (21 CFR Part 11 §11.10(d); EU GMP Annex 11 §4, §12) | Yes | retain all versions | Quality Assurance | Version history + administrator electronic signatures |
| Single-sign-on configuration (versioned) | Identity-federation configuration evidence (EU GMP Annex 11 §12) | Yes | retain history | Information Security / QA | Version history + administrator electronic signatures |

The predicate-rule applicability matrix is a controlled artefact of this URS. Updating it is a Class 1 change per §7.

---

## 15. URS Requirements Register

### 15.1 Front-end (FE)

- URS-01-FE-001 — Login screen renders e-mail and password fields and single-sign-on buttons; single-sign-on buttons appear only after the lookup query resolves. Priority MUST. Risk LOW. Maps RG-01-001.
- URS-01-FE-002 — `useLogin` MUST NOT set `isAuthenticated = true` on a multi-factor required response or a tenant-selection response. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-FE-003 — Front end stores user, Cross-Site Request Forgery token, and Authority Context atomically through a single auth-state setter on every login, refresh, bootstrap, and multi-factor completion success. Priority MUST. Risk MEDIUM. Maps RG-01-009.
- URS-01-FE-004 — Front end MUST NOT include `ip`, `userAgent`, `timestamp`, or `performedBy` in any request body. Priority MUST. Risk HIGH. Maps RG-01-004.
- URS-01-FE-005 — `<AuthorityGuard>` renders disabled buttons when the Authority Context is null or the required profile is missing, with tooltip "Requires [profile] authority" or "Authority context unavailable". Priority MUST. Risk MEDIUM. Maps RG-01-002.
- URS-01-FE-006 — `<AuthorityGuard>` MUST be present on every approve, release, dispose, sign-off, delegate, final-review, closure, and override button across all modules. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-FE-007 — `<SessionTimeoutWarning>` MUST NOT start a countdown until the session policy returns. Priority MUST. Risk LOW. Maps RG-01-009.
- URS-01-FE-008 — `<SessionTimeoutWarning>` MUST NOT contain a hard-coded idle-timeout fallback; absent a server policy response, the timer does not run. Priority MUST. Risk LOW. Maps RG-01-009.
- URS-01-FE-009 — On `403 CSRF_INVALID`, the user interface MUST show a toast and silently call bootstrap to recover the Cross-Site Request Forgery token; the user interface MUST NOT auto-retry the failing request. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-FE-010 — Every route in §5.1 MUST be registered in the application router before release. Priority MUST. Risk LOW. Maps RG-01-009.
- URS-01-FE-011 — Login form MUST disable submit during async submission. Priority MUST. Risk LOW. Maps RG-01-001.
- URS-01-FE-012 — Multi-factor challenge field auto-submits on a six-digit numeric entry. Priority SHOULD. Risk LOW.
- URS-01-FE-013 — Password fields render a live policy indicator driven by the password policy endpoint. Priority MUST. Risk LOW. Maps RG-01-006.
- URS-01-FE-014 — Force-password-change UI disables every other navigation until completion. Priority MUST. Risk MEDIUM. Maps RG-01-006.
- URS-01-FE-015 — The session list page MUST display `last_active_at`. Priority MUST. Risk LOW. Maps RG-01-009.
- URS-01-FE-016 — A persistent banner displays "Authority context unavailable — approval actions temporarily disabled." whenever the Authority Context status is `unavailable`. Priority MUST. Risk MEDIUM. Maps RG-01-011.
- URS-01-FE-017 — Every regulated administrative action routes through the Controlled Approval Modal. Priority MUST. Risk HIGH. Maps RG-01-004, RG-01-005.
- URS-01-FE-018 — Submission of any regulated action requires a non-empty meaning of signature and reason for change. Priority MUST. Risk HIGH. Maps RG-01-004.

### 15.2 Back-end (BE)

- URS-01-BE-001 — Login returns a login response with user, Cross-Site Request Forgery token, Authority Context, and (optional) requires-password-change indicator on full-authentication success. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-BE-002 — JSON Web Token MUST include the claims version on every issuance; the shared payload type marks the field required. Priority MUST. Risk MEDIUM. Maps RG-01-002.
- URS-01-BE-003 — Bootstrap regenerates and returns Cross-Site Request Forgery token in body and returns Authority Context. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-BE-004 — When the Authority Resolver fails, login, refresh, bootstrap, and multi-factor complete MUST return `503 AUTHZ_CONTEXT_RESOLUTION_FAILED` with `authzContextStatus: 'unavailable'`. Priority MUST. Risk MEDIUM. Maps RG-01-011.
- URS-01-BE-005 — Refresh-time claims-version mismatch with regulated authority revocation OR base-role downgrade MUST revoke the session and return `401 SESSION_REVOKED_AUTHORITY_CHANGE`. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-BE-006 — Invitation acceptance and single-sign-on callback MUST NOT auto-assign any Authority Profile. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-BE-007 — Hash-chained logs MUST use database advisory locks for serialised writes. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-BE-008 — Authority writes MUST atomically increment the affected user(s)' claims version in the same transaction as the change-log write. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-BE-009 — Auto-expiry job runs no less frequently than hourly, attributes to the system identity, and emits the expiry events. Priority MUST. Risk MEDIUM. Maps RG-01-003.
- URS-01-BE-010 — All twelve authority-event codes have at least one writer code path; pull-request-level static-analysis gate enforces this. Priority MUST. Risk MEDIUM. Maps RG-01-003.
- URS-01-BE-011 — The six error codes (AUTHZ_CONTEXT_RESOLUTION_FAILED, AUTHORITY_CHECK_FAILED, DELEGATION_INVALID, CLAIMS_VERSION_MISMATCH, SESSION_REVOKED_AUTHORITY_CHANGE, AUTHORITY_STATE_INCONSISTENT) MUST each have at least one emission path covered by an integration test. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-BE-012 — Back end silently drops any client-supplied `ip`, `userAgent`, `timestamp`, or `performedBy` field; electronic-signature metadata is always server-derived. Priority MUST. Risk HIGH. Maps RG-01-004.
- URS-01-BE-013 — Stale-claims request flag MUST cause the authority-check hook to deny regulated routes with `401 CLAIMS_VERSION_MISMATCH` (Mode B for regulated routes). Priority MUST. Risk MEDIUM. Maps RG-01-002.
- URS-01-BE-014 — Password change, password reset, and invitation acceptance MUST validate against the password policy and append to password history. Priority MUST. Risk MEDIUM. Maps RG-01-006.
- URS-01-BE-015 — Refresh-token reuse detection MUST revoke all sessions of the user and emit `TOKEN_REUSE_DETECTED`. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-BE-016 — Session fingerprint MUST normalise IPv4 to /24 and IPv6 to /64, and user agent to a 200-character normalised form. Priority MUST. Risk LOW. Maps RG-01-001.
- URS-01-BE-017 — Single-sign-on callback MUST redirect to the front-end origin root after a successful exchange. Priority MUST. Risk LOW. Maps RG-01-001.
- URS-01-BE-018 — Login rate-limit ten per minute per IP and thirty per hour per account; multi-factor challenge ten per minute per (challenge, IP). Priority MUST. Risk LOW. Maps RG-01-001.
- URS-01-BE-019 — Multi-factor challenges MUST persist attempts and maximum attempts; on exhaustion the challenge is locked and login restarts. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-BE-020 — Every table within this module's data scope MUST have Row-Level Security enabled in the same migration that creates it. Priority MUST. Risk HIGH. Maps RG-01-009.

### 15.3 Workflow (WF)

- URS-01-WF-001 — Session state machine adheres to §5.4 transitions; no transition occurs without the documented audit event. Priority MUST. Risk MEDIUM. Maps RG-01-003.
- URS-01-WF-002 — Authority Assignment state machine adheres to §5.4 transitions; revoke (regulated) cascades to revoke-all-sessions. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-WF-003 — Delegation effective-to is non-null and strictly greater than effective-from. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-WF-004 — Auto-expiry job runs no less frequently than hourly with system attribution. Priority MUST. Risk MEDIUM. Maps RG-01-002.

### 15.4 Data (DATA)

- URS-01-DATA-001 — Every entity in §6.1 exists with the columns and constraints in §6.2; uniqueness is enforced at the database level. Priority MUST. Risk HIGH. Maps RG-01-009.
- URS-01-DATA-002 — Authority change log rows are append-only and hash-chained. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-DATA-003 — Authentication audit log rows are append-only and hash-chained. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-DATA-004 — Soft-deleted rows remain queryable for audit and export paths. Priority MUST. Risk MEDIUM. Maps RG-01-014.
- URS-01-DATA-005 — Versioned policy tables retain all historical versions accessible by version and effective-from. Priority MUST. Risk MEDIUM. Maps RG-01-008.
- URS-01-DATA-006 — Global Authority Profiles MUST carry the system flag set, and the system-profile guard MUST prevent deactivation or relabelling. Profile keys MUST be immutable once referenced by an active assignment, delegation, scope rule, or workflow node. Priority MUST. Risk HIGH. Maps RG-01-009.

### 15.5 Security (SEC)

- URS-01-SEC-001 — All requests route through Tenant Data Access Layer. Priority MUST. Risk CRITICAL. Maps RG-01-009.
- URS-01-SEC-002 — Cookies are HttpOnly, Secure (in production), `SameSite=Lax`; refresh-cookie path is the refresh endpoint. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-SEC-003 — All secrets at rest encrypted via cloud Key Management Service; key rotation at least annually. Priority MUST. Risk HIGH. Maps RG-01-009.
- URS-01-SEC-004 — Refresh-token storage is hashed; the raw token is never persisted. Priority MUST. Risk HIGH. Maps RG-01-001.
- URS-01-SEC-005 — TLS 1.2 or higher with HTTP Strict Transport Security preload and current OWASP cipher suites. Priority MUST. Risk HIGH. Maps RG-01-009.
- URS-01-SEC-006 — Logs scrub passwords, tokens, multi-factor secrets, and single-sign-on secrets. Priority MUST. Risk HIGH. Maps RG-01-016.
- URS-01-SEC-007 — The system identity `system@verixa.internal` MUST resolve to a real user row used by all auto-attributed jobs; the literal `'system'` is forbidden as actor for any user-invoked route. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-SEC-008 — Periodic access review MUST be performed per §12.10: at least quarterly for GxP-critical tenants and at least semi-annually for non-critical tenants; reviews MUST be electronically signed by an independent reviewer and retained for the same period as the authority change log; unresolved exceptions MUST create either a CAPA (URS-18) or a security deviation (URS-16) within five business days. Priority MUST. Risk HIGH. Maps RG-01-001, RG-01-009.
- URS-01-SEC-009 — Periodic audit-trail review MUST be performed per §12.11 with high-risk events triaged within one business day, routine review documented at least monthly, and every triage decision electronically signed by the reviewer and persisted into the authority change log. Priority MUST. Risk HIGH. Maps RG-01-003, RG-01-008.

### 15.6 Audit (AUD)

- URS-01-AUD-001 — Every state-changing action emits an audit event with all required fields per §6.6. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-AUD-002 — Server-derived metadata is the only source of truth for audit fields. Priority MUST. Risk HIGH. Maps RG-01-004.
- URS-01-AUD-003 — Audit-log write failure rolls back the originating action. Priority MUST. Risk CRITICAL. Maps RG-01-003.
- URS-01-AUD-004 — All thirty documented audit and event codes (eighteen authentication and twelve authority) have at least one writer. Priority MUST. Risk MEDIUM. Maps RG-01-003.
- URS-01-AUD-005 — Hash-chain integrity verifier is exposed as a callable endpoint and as a command-line tool for restore drills. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-AUD-006 — The substrate MUST expose review-supporting endpoints for periodic audit-trail review per §6.6.1: filterable read of the authentication audit log and the authority change log; integrity-verifier over a configured window; reviewer-attached triage decision (security incident / deviation / CAPA / no-impact) with electronic signature persisted into the authority change log under a dedicated event code. Priority MUST. Risk HIGH. Maps RG-01-003, RG-01-008.

### 15.7 Electronic Signature (ESIG)

- URS-01-ESIG-001 — Every regulated administrative action is electronically signed; the modal collects only password, meaning of signature, reason for change. Priority MUST. Risk HIGH. Maps RG-01-004.
- URS-01-ESIG-002 — Signature row carries server-derived IP, user agent, signed-at, signed-by. Priority MUST. Risk HIGH. Maps RG-01-004.
- URS-01-ESIG-003 — Signature is linked to the action row; subsequent change to the signed entity invalidates the signature. Priority MUST. Risk MEDIUM. Maps RG-01-005.
- URS-01-ESIG-004 — Electronic signature requires re-authentication via password; high-risk actions require multi-factor step-up. Priority MUST. Risk MEDIUM. Maps RG-01-004.
- URS-01-ESIG-005 — Before a user is permitted to execute an electronic signature, the tenant MUST verify the user's identity, capture the user's electronic acknowledgement of the tenant's electronic-signature policy stating that electronic signatures are legally binding equivalents of handwritten signatures, and persist identity-verification evidence, signature-policy acknowledgement, and signature activation date per §6.7.1. Priority MUST. Risk HIGH. Maps RG-01-004 (21 CFR Part 11 §11.100, §11.200, §11.300).
- URS-01-ESIG-006 — Identification codes MUST NOT be re-used across users; deactivation of a user MUST NOT free the identifier for assignment to a new individual. Priority MUST. Risk HIGH. Maps RG-01-006 (21 CFR Part 11 §11.300).

### 15.8 AI / Human-in-the-Loop (AI)

- URS-01-AI-001 — No AI or large-language model is invoked in any authentication or authorisation decision path. Priority MUST. Risk HIGH. Maps RG-01-018.
- URS-01-AI-002 — When the MIRA agent is invoked from other modules, it receives Authority Context for downstream gating but MUST NOT mutate authentication state. Priority MUST. Risk MEDIUM. Maps RG-01-018.

### 15.9 Integration (INT)

- URS-01-INT-001 — URS-02 receives base role on every request and uses it for coarse access. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-INT-002 — URS-03 receives effective scopes and tenant identifier for context-gating. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-INT-003 — URS-04 receives Authority Context and electronic-signature identifier for human-in-the-loop and electronic-signature gating. Priority MUST. Risk HIGH. Maps RG-01-002.
- URS-01-INT-004 — URS-05 owns authority business semantics; URS-01 owns the substrate (resolver, change log, claims version). Priority MUST. Risk MEDIUM. Maps RG-01-002.
- URS-01-INT-005 — URS-08 active-tenant status gates session creation; an inactive tenant returns the `TENANT_INACTIVE` error code. Priority MUST. Risk MEDIUM. Maps RG-01-001.
- URS-01-INT-006 — URS-30 delivers all notifications listed in §10. Priority MUST. Risk LOW. Maps RG-01-020.
- URS-01-INT-007 — URS-35 preserves hash-chain integrity across restore. Priority MUST. Risk HIGH. Maps RG-01-011.

### 15.10 Reports / Exports (REP)

- URS-01-REP-001 — All reports in §9 are implemented with the documented filters, columns, formats, and access rules. Priority MUST. Risk MEDIUM. Maps RG-01-009.
- URS-01-REP-002 — Authority-log export produces a self-verifying integrity manifest; exports are electronically signed. Priority MUST. Risk HIGH. Maps RG-01-003.
- URS-01-REP-003 — Export download URLs are signed and time-to-live limited (fifteen minutes). Priority MUST. Risk MEDIUM. Maps RG-01-016.

### 15.11 Validation Evidence (VAL)

- URS-01-VAL-001 — An IQ pack verifies the schema of all migrations creating Module 1 tables; Row-Level Security enabled on every table. Priority MUST. Risk HIGH. Maps RG-01-007.
- URS-01-VAL-002 — An OQ pack tests the Authority Resolver, login Authority Context, JSON Web Token claims version, refresh-time critical-change revoke, `<AuthorityGuard>` component, authority administration API, all thirty audit / event codes, all six error codes, hash-chain integrity, and Cross-Site Request Forgery regeneration on bootstrap. Priority MUST. Risk HIGH. Maps RG-01-007.
- URS-01-VAL-003 — A PQ pack runs end-to-end scenarios for: login → refresh → bootstrap → approval action gated by `<AuthorityGuard>`; single-sign-on callback; multi-factor challenge; authority administration lifecycle (assign, delegate, revoke, expire); authority-triggered session invalidation; audit-replay verifying chain integrity. Priority MUST. Risk HIGH. Maps RG-01-007.
- URS-01-VAL-004 — A regression pack MUST exercise every requirement in §15 so a future change cannot silently invalidate any documented behaviour; the pack is run on every release candidate. Priority MUST. Risk MEDIUM. Maps RG-01-007.
- URS-01-VAL-005 — A traceability matrix links each requirement identifier in §15 to at least one IQ, OQ, or PQ test case. Priority MUST. Risk HIGH. Maps RG-01-007.
- URS-01-VAL-006 — A supplier and service-provider qualification pack MUST exist per §17.1 covering cloud hosting, Key Management Service, e-mail / notification provider, single-sign-on / identity provider, backup and restore provider, security-operations / SIEM alert routing, service-level agreements, incident response, and right-to-audit / inspection-support clauses. Priority MUST. Risk HIGH. Maps RG-01-007 (FDA CSA Final Guidance February 2026; EU GMP Annex 11 §3 — Suppliers and Service Providers).
- URS-01-VAL-007 — An inspection-ready evidence index MUST exist per §17.2 linking each URS requirement through Functional Specification, Design Specification, source code reference, test protocol, executed evidence, deviations, and release approval, electronically signed by the validation lead and retained per Annex 11 §17. Priority MUST. Risk HIGH. Maps RG-01-007, RG-01-015.
- URS-01-VAL-008 — Migration Evidence Gate. Before Installation Qualification execution, engineering MUST provide the exact migration set proving all §6.2 entities, columns, constraints, indexes, Row-Level Security policies, append-only protections, hash-chain fields, and seed data; Installation Qualification MUST fail if any migration evidence is missing. Priority MUST. Risk CRITICAL. Maps RG-01-007.

---

## 16. Acceptance Criteria and Test Cases

This section is read by three audiences with different needs:

- Product owners and business validators read §16.1 *Plain-language behaviour scenarios*.
- Engineering and test automation read §16.2 *Technical test cases*.
- Quality / validation engineers read §16.3 *Acceptance criteria summary in Given / When / Then form* plus §16.4 *Requirements ↔ test cases traceability*.

### 16.1 Plain-language behaviour scenarios

#### TC-PLAIN-001 — Brute-force password attempts are blocked

- An attacker types the wrong password again and again. After five wrong attempts within fifteen minutes the account is locked; further attempts return a clear message; the user receives a notification e-mail; the lockout clears automatically after fifteen minutes or by administrator action.

#### TC-PLAIN-002 — Idle session expires safely

- A user logs in at 09:00 and leaves their desk. At 09:28 a banner warns "Your session will sign out in 2 minutes." At 09:30 the screen redirects to login and the server has revoked the session.

#### TC-PLAIN-003 — Revoking an authority kicks the user out of all open tabs

- An administrator revokes a user's regulated approval right while the user has Verixa open in another tab. Within seconds the user's session is killed; the user is redirected to login with an explanatory message; on next login the approve buttons are disabled.

#### TC-PLAIN-004 — Time-bound delegation hands approval rights for a fortnight

- A user delegates the right to approve to a colleague from 1 August to 14 August with a reason. The colleague gains the rights in scope; the system auto-expires the delegation at midnight on 14 August; both parties receive notification e-mails.

#### TC-PLAIN-005 — The system cannot fake who signed an approval

- A penetration tester sends an approval request with spoofed source IP, user agent, timestamp, and actor. The audit row carries the real network IP, real browser user agent, the server clock, and the user identifier from the active session; the spoofed values appear nowhere.

#### TC-PLAIN-006 — Failed audit write blocks the action

- During peak load the audit-log write fails while the user is approving a record. The approval does not commit; the user sees a clear error; the regulated record is unchanged.

#### TC-PLAIN-007 — Account deactivation is enforced immediately

- An administrator deactivates a user. The user's open sessions are revoked; the next request returns the dedicated error code; an attempt to log in returns "Your account has been deactivated."

#### TC-PLAIN-008 — Cross-tenant data is invisible to other tenants

- A penetration tester logged in as Tenant A's user attempts to read a record they know exists in Tenant B. Every attempt returns a denial; no Tenant B data is ever returned in any response.

#### TC-PLAIN-009 — Concurrent revokes do not break the audit chain

- Two administrators click "Revoke" simultaneously. Both clicks are processed in order; the audit chain remains unbroken; one electronic signature per administrator click.

#### TC-PLAIN-010 — Network-prefix mobility is tolerated; foreign network triggers a security event

- A user moves between offices on the same network; the session continues. A user's session token replayed from a different network triggers session revocation, a security alert, and an e-mail to the user.

#### TC-PLAIN-011 — Single-sign-on does not grant approval rights automatically

- A new employee signs in via single-sign-on for the first time. They have read-only access; every approve button is disabled until an administrator explicitly assigns an Authority Profile.

#### TC-PLAIN-012 — Resolver outage degrades safely

- The Authority Resolver cannot read its database for two minutes. Users remain logged in for read-only views; a banner indicates "Authority context unavailable — approval actions temporarily disabled"; every regulated button is disabled; the security operations centre receives the alert; once the resolver recovers, the banner clears on the next bootstrap poll.

#### TC-PLAIN-013 — Records remain reconstructable after years

- An inspector points at a record closed three years ago and asks for the signer's identity, the active Authority Profile of the signer at that moment, and the un-tampered hash chain. The system produces all three on demand.

### 16.2 Technical test cases

#### TC-TECH-001 — Login (no multi-factor authentication, single tenant) returns full login response

- Audience: Backend Engineer, Test Engineer.
- Type: Integration.
- Linked requirements: URS-01-BE-001, URS-01-BE-002, URS-01-FE-002, URS-01-FE-003, BR-01-07.
- Preconditions: Tenant T1 is active; user u1 is a quality_lead member of T1; no multi-factor enrolment; no active lockout; IP allowlist permits the test runner.
- Steps:
  1. POST `/api/v1/auth/login` with `{email, password}`.
  2. Capture HTTP response.
  3. Decode the JSON Web Token in the access cookie.
  4. Read the latest authentication audit row for u1.
  5. Read the latest session row for u1.
- Expected results: HTTP 200 with `LoginResponse` carrying user, csrfToken, authzContext (baseRole = quality_lead, claimsVersion ≥ 1, tenantId in effectiveScopes); cookies are HttpOnly, Secure (production), SameSite=Lax; refresh cookie path = refresh endpoint; JSON Web Token carries claimsVersion (required); `auth_audit_log` row event = login_success with hash chain valid; session row claims_version matches token.
- Pass criterion: all expected results pass.

#### TC-TECH-002 — Login with multi-factor authentication does not authenticate prematurely

- Audience: Backend Engineer, Frontend Engineer, Test Engineer.
- Type: Integration + End-to-end.
- Linked requirements: URS-01-FE-002, URS-01-BE-019, BR-01-19.
- Preconditions: User u2 has an active multi-factor enrolment.
- Steps:
  1. POST login for u2.
  2. Inspect response and cookies.
  3. Inspect front-end auth store after `useLogin.onSuccess`.
  4. Compute current TOTP for the secret.
  5. POST `/auth/mfa/complete` with challenge and token.
  6. Inspect response and cookies.
- Expected results: Step 1 returns `{mfaRequired:true, mfaChallenge, methods:['totp']}` and **no** `Set-Cookie` for access or refresh; auth store remains `isAuthenticated = false`; Step 5 returns full login response with cookies; audit row `mfa_success`.
- Pass criterion: all conditions hold.

#### TC-TECH-003 — Multi-factor brute-force is rate-limited and the challenge expires

- Type: Integration.
- Linked requirements: URS-01-BE-018, URS-01-BE-019, BR-01-06.
- Steps: 1. Login for u2; capture challenge. 2. Submit ten incorrect TOTPs. 3. Submit eleventh request from same IP. 4. Wait six minutes (challenge time-to-live is five minutes). 5. Submit (now-correct) TOTP.
- Expected: Step 2 each returns 401 MFA_INVALID_CODE; Step 3 returns 429; Step 5 returns 401 MFA_CHALLENGE_EXPIRED; audit shows mfa_challenge_exhausted.

#### TC-TECH-004 — Bootstrap regenerates Cross-Site Request Forgery and returns Authority Context

- Type: Integration + End-to-end.
- Linked requirements: URS-01-BE-003, URS-01-FE-009.
- Steps: 1. GET bootstrap with valid access cookie. 2. Compare csrfToken to previous request's. 3. Inspect body for authzContext.
- Expected: new csrfToken; authzContext fully populated; audit emits authz_context_resolved.

#### TC-TECH-005 — Single-sign-on callback creates JIT user with viewer-only

- Type: Integration.
- Linked requirements: URS-01-BE-006, BR-01-12, J-07.
- Steps: 1. GET single-sign-on initiation; follow 302 to mock identity provider. 2. Mock identity provider returns 302 to callback. 3. Backend exchanges code; mints session. 4. SELECT users, memberships, user_authority_assignments for new user. 5. Inspect cookies and final 302 destination.
- Expected: exactly one user row (status active); one membership row (role viewer); zero authority assignments; final 302 target equals front-end origin root.

#### TC-TECH-006 — Session idle timeout enforces server-side and front-end has no fallback

- Type: End-to-end + Static analysis.
- Linked requirements: URS-01-FE-007, URS-01-FE-008, URS-01-BE-016.
- Preconditions: Session policy idle_timeout_minutes = 30. User u1 logged in.
- Steps: 1. Static analysis of front-end source for hard-coded idle-timeout fallback. 2. Mount session-timeout warning component with no policy yet returned. 3. Wait twenty-eight minutes; verify warning. 4. Wait two more minutes; verify redirect. 5. From a separate test context, attempt to use the original token.
- Expected: Step 1 zero matches; Step 2 no countdown begins until policy returns; Step 4 server returns 401 on the next request even if the browser stays open.

#### TC-TECH-007 — Session hijack detection on fingerprint mismatch

- Type: Integration.
- Linked requirements: URS-01-BE-016, J-18.
- Preconditions: u1 active session at 203.0.113.45 (chrome/macOS user agent).
- Steps: 1. Replay the JWT from a request with source IP 198.51.100.7 (different /24). 2. Same JWT, same IP, but user agent changed.
- Expected: each returns 401 SESSION_HIJACK_DETECTED; session row `revoked`; audit row session_hijack_detected with both fingerprints.

#### TC-TECH-008 — Authority revoke (regulated) cascades session invalidation

- Type: Integration + End-to-end.
- Linked requirements: URS-01-BE-005, URS-01-WF-002, BR-01-09, BR-01-21, J-12.
- Preconditions: u1 holds active assignment of `final_quality_approver`; u1 has two active sessions; administrator a1 has tenant_admin authority.
- Steps: 1. Administrator calls DELETE on the assignment with valid electronic-signature payload. 2. u1 (session 1) calls a non-regulated read endpoint. 3. Force a refresh from session 1. 4. SELECT from authority_change_log, user_tenant_authz_state, user_sessions.
- Expected: Step 1 returns 204; rows in authority_change_log: AUTHORITY_REVOKED (regulated true), CLAIMS_VERSION_INCREMENTED, two SESSION_REVOKED_AUTHORITY_CHANGE; Step 2 succeeds (Mode A applies at refresh); Step 3 returns 401 SESSION_REVOKED_AUTHORITY_CHANGE; all sessions revoked; claims_version incremented exactly once.

#### TC-TECH-009 — Audit-log write failure rolls back the originating action

- Type: Integration (chaos test) + Manual verification.
- Linked requirements: URS-01-AUD-003, BR-01-17.
- Steps: 1. Begin a transaction by calling DELETE on an authority assignment with valid electronic signature. 2. Test harness throws on audit-log INSERT. 3. Inspect user_authority_assignments, electronic_signatures, authority_change_log.
- Expected: no rows changed; HTTP 500 AUDIT_TRAIL_WRITE_FAILED; user retry returns to consistent state.

#### TC-TECH-010 — Concurrent authority writes preserve hash-chain integrity

- Type: Concurrency.
- Linked requirements: URS-01-BE-007, URS-01-AUD-005.
- Steps: Fire 100 parallel POSTs to assignments. Run chain integrity verifier on authority_change_log.
- Expected: all 100 rows present; chain unbroken from genesis.

#### TC-TECH-011 — Authority-log export carries integrity manifest and is electronically signed

- Type: Integration + Manual.
- Linked requirements: URS-01-REP-002, URS-01-REP-003.
- Steps: 1. Administrator POSTs to audit/export with range, filters, electronic-signature payload. 2. Server returns signed download URL with TTL fifteen minutes. 3. Download contents. 4. Recompute hash chain on included rows.
- Expected: manifest contains start_hash, end_hash, row_count, validation_status pass; signed URL expires in fifteen minutes; electronic signature recorded.

#### TC-TECH-012 — Resolver outage returns 503 with correlation identifier; UI gates buttons; SOC alerted

- Type: Chaos + End-to-end.
- Linked requirements: URS-01-BE-004, URS-01-FE-016, J-19.
- Steps: 1. Toggle resolver into a failure mode. 2. GET bootstrap. 3. Verify front-end UI. 4. Verify SOC alert pipeline.
- Expected: 503 AUTHZ_CONTEXT_RESOLUTION_FAILED with correlation identifier and authzContextStatus 'unavailable'; banner appears; AuthorityGuard buttons disabled with tooltip; alert delivered.

#### TC-TECH-013 — Delegation: mandatory effective-to and auto-expiry

- Type: Integration.
- Linked requirements: URS-01-WF-003, URS-01-BE-009, BR-01-14, BR-01-15, J-15.
- Steps: 1. POST delegation with effective_to = null → expect 400 DELEGATION_INVALID. 2. POST with effective_to = effective_from minus one minute → expect 400. 3. POST with effective_to = NOW + one minute; trigger auto-expiry job manually after ninety minutes; check status. 4. Verify DELEGATION_EXPIRED event with system actor.
- Expected: Steps 1–2 reject; Step 3 transitions to expired within sixty minutes; Step 4 row exists.

#### TC-TECH-014 — Client-supplied attribution fields are silently dropped

- Type: Integration + Penetration.
- Linked requirements: URS-01-FE-004, URS-01-BE-012, URS-01-AUD-002, URS-01-ESIG-002, BR-01-19.
- Steps: 1. POST login with body containing spoofed ip, userAgent, timestamp. 2. POST authority assignment with valid electronic-signature payload also containing spoofed ip, user_agent, signed_at, performedBy. 3. SELECT auth_audit_log and electronic_signatures rows.
- Expected: every field in both rows reflects server-derived values; spoofed values appear nowhere.

#### TC-TECH-015 — Force-password-change blocks all other navigation

- Type: End-to-end.
- Linked requirements: URS-01-FE-014, J-04.
- Preconditions: u1 has force_password_change = true.
- Steps: 1. u1 logs in. 2. Attempt direct URL navigation to dashboard. 3. Submit valid new password.
- Expected: Step 1 redirects to change-password; Step 2 cannot navigate; Step 3 succeeds and revokes all other sessions.

#### TC-TECH-016 — Account lockout fires at threshold; administrator can unlock

- Type: Integration + End-to-end.
- Linked requirements: URS-01-BE-018, BR-01-05, BR-01-06, J-16.
- Preconditions: Lockout policy: 5 / 15-minute window / 15-minute lock.
- Steps: 1. Five failed login attempts within five minutes. 2. Sixth with correct password. 3. Administrator POST unlock with reason and electronic signature. 4. Retry with correct password.
- Expected: Step 2 returns 423 with lockedUntil; audit account_lockout. Step 4 returns 200; audit account_unlock and login_success.

#### TC-TECH-017 — Claims version is strictly monotonic per (user, tenant)

- Type: Concurrency.
- Linked requirements: URS-01-BE-008, BR-01-21.
- Steps: Fire 100 concurrent claims-version increments for u1 in T1.
- Expected: final value = previous + 100; no duplicates; sequence strictly increasing.

#### TC-TECH-018 — Refresh-token reuse triggers session revoke and audit

- Type: Integration.
- Linked requirements: URS-01-BE-015.
- Steps: 1. POST refresh; capture old refresh token. 2. Use new token successfully. 3. Replay old token.
- Expected: Step 3 returns 401 TOKEN_REUSE_DETECTED; all sessions revoked; audit refresh_token_reuse_detected and bulk session_revoke.

#### TC-TECH-019 — Cross-tenant data isolation cannot be bypassed

- Type: Penetration + Database-level.
- Linked requirements: URS-01-SEC-001, URS-01-BE-020.
- Steps: 1. Authenticate as Tenant A user. Enumerate every authenticated endpoint and attempt to fetch known Tenant B records. 2. Database session set tenant context to Tenant A and attempt SELECT of Tenant B rows. 3. Verify migrations: every Module 1 table has Row-Level Security enabled.
- Expected: Step 1 all 403/404 with no Tenant B data; Step 2 empty result; Step 3 all tables pass.

#### TC-TECH-020 — Performance: login p95 ≤ 500 ms at 1 000 RPS

- Type: Load.
- Linked requirements: AC-01-PERF-01.
- Steps: Sustain 1 000 requests per second of valid logins for fifteen minutes against a production-like environment.
- Expected: p50 ≤ 200 ms, p95 ≤ 500 ms, error rate < 0.1 %.

#### TC-TECH-021 — Performance: refresh p95 ≤ 200 ms at 5 000 RPS

- Type: Load.
- Linked requirements: AC-01-PERF-02.
- Steps: 5 000 requests per second sustained for fifteen minutes.
- Expected: p95 ≤ 200 ms; error rate < 0.1 %.

#### TC-TECH-022 — Migrations are idempotent and create schema with Row-Level Security

- Type: Migration.
- Linked requirements: URS-01-DATA-001, URS-01-BE-020, AC-01-MIG-01, AC-01-MIG-02.
- Steps: 1. Apply all Module 1 migrations against a clean database. 2. Apply them all again. 3. Inspect schema: every entity in §6.1 exists; every table has Row-Level Security enabled; canonical seed of Authority Profiles loaded.
- Expected: no errors on re-apply; no schema drift between runs.

#### TC-TECH-023 — Three-layer guard hierarchy (front-end static analysis)

- Type: Static analysis.
- Linked requirements: URS-01-FE-006, §0.4 item 1.
- Steps: 1. Walk the front-end abstract syntax tree for every button labelled approve, release, dispose, sign, close, reject, override, delegate. 2. For each, verify it is wrapped — directly or transitively — by `<AuthorityGuard>`.
- Expected: zero unwrapped regulated buttons.

#### TC-TECH-024 — All thirty audit / event codes have at least one writer

- Type: Static analysis + Integration.
- Linked requirements: URS-01-AUD-004, URS-01-BE-010.
- Steps: 1. Static grep across server source: each of the eighteen authentication and twelve authority codes appears in at least one writer file. 2. Run a regression suite that triggers every code at least once and asserts each row appears in the corresponding log.
- Expected: 30 / 30 vocabulary coverage.

#### TC-TECH-025 — Six error codes are emitted by some path

- Type: Integration.
- Linked requirements: URS-01-BE-011.
- Steps: One integration test per code (AUTHZ_CONTEXT_RESOLUTION_FAILED, AUTHORITY_CHECK_FAILED, DELEGATION_INVALID, CLAIMS_VERSION_MISMATCH, SESSION_REVOKED_AUTHORITY_CHANGE, AUTHORITY_STATE_INCONSISTENT).
- Expected: each test triggers the documented HTTP status and code.

### 16.3 Acceptance criteria summary in Given / When / Then form

#### Functional

- AC-01-FUN-01 — Given a valid user without multi-factor authentication, When they POST login, Then the response is 200 with `{user, csrfToken, authzContext}` and Set-Cookie for access and refresh.
- AC-01-FUN-02 — Given a multi-factor-enrolled user, When they POST login, Then the response is 200 `{mfaRequired:true, mfaChallenge, methods:['totp']}` and no cookies are set.
- AC-01-FUN-03 — Given a multi-factor challenge token within time-to-live, When the user POSTs multi-factor complete with the correct TOTP, Then a full login response is returned and cookies are set.
- AC-01-FUN-04 — Given a user with `force_password_change = true`, When they log in, Then the response carries `requiresPasswordChange:true` and `authzContext = null`, and the user interface navigates to change-password with all other navigation disabled.
- AC-01-FUN-05 — Given a successful change-password, When the response returns 200, Then all other sessions of the user are revoked and claims version increments.

#### User interface

- AC-01-UI-01 — Given Authority Context is null, When `<AuthorityGuard authority="x">` mounts, Then the wrapped button is disabled with tooltip "Authority context unavailable".
- AC-01-UI-02 — Given a six-digit numeric input on multi-factor challenge, When the sixth digit is entered, Then the form auto-submits.
- AC-01-UI-03 — Given an idle session approaching idle limit, When two minutes remain, Then the timeout warning appears with "Stay signed in" / "Sign out".

#### Application Programming Interface

- AC-01-API-01 — Given an authenticated bootstrap, When the resolver succeeds, Then the response carries user, regenerated csrfToken, and authzContext.
- AC-01-API-02 — Given the resolver fails, When bootstrap is called, Then the response is 503 with code AUTHZ_CONTEXT_RESOLUTION_FAILED and the user identity payload.
- AC-01-API-03 — Given a JSON Web Token claims_version = N and persisted = N+1 with a regulated AUTHORITY_REVOKED, When refresh runs, Then the response is 401 SESSION_REVOKED_AUTHORITY_CHANGE and the session row is revoked.

#### Workflow

- AC-01-WF-01 — Given an active delegation with effective_to in the past, When the auto-expiry job runs, Then the delegation status becomes expired, DELEGATION_EXPIRED is logged with system attribution, and both users' claims version increments.

#### Permissions

- AC-01-PERM-01 — Given a viewer user, When they POST authority assignments, Then 403.
- AC-01-PERM-02 — Given a tenant_admin user, When they POST authority assignments for a profile with a segregation-of-duties violation, Then 403 SOD_VIOLATION with rule identifier in details.

#### Audit

- AC-01-AUD-01 — Given any authority change is committed, When the audit transaction is rolled back (forced failure), Then the authority change is also rolled back and no row appears in authority_change_log or user_authority_assignments.
- AC-01-AUD-02 — Given 100 parallel authority changes for the same tenant, When the writes complete, Then `authority_change_log.record_hash` chain is unbroken from genesis.

#### Electronic signature

- AC-01-ESIG-01 — Given an administrator attempts to PUT password policy without an active electronic-signature session, Then the response is 422 ESIG_REQUIRED.
- AC-01-ESIG-02 — Given a successful electronic signature on policy edit, When the row is written, Then `electronic_signatures.signed_by = req.user.id`, `signed_at = NOW()`, `ip = req.ip`, `user_agent = req.headers['user-agent']`. Client-supplied values for those fields are dropped.

#### Data integrity

- AC-01-DI-01 — Given a soft-deleted user, When administrator queries the audit-export endpoint, Then the user appears in audit history.
- AC-01-DI-02 — Given a versioned password policy row, When a new version is published, Then the previous row is superseded with effective_to = new.effective_from.

#### Integration

- AC-01-INT-01 — Given a downstream module requests an approval, When the user lacks the required Authority Profile, Then `<AuthorityGuard>` disables the button and the authority-check hook returns 403 AUTHORITY_CHECK_FAILED with rule attribution.
- AC-01-INT-02 — Given URS-35 restores a database snapshot, When the integrity verifier runs, Then both authentication audit log and authority change log chains validate end-to-end.

#### Report and export

- AC-01-REP-01 — Given an administrator exports the authority change log, When the download completes, Then the manifest includes the chain start_hash, end_hash, row_count, and validation status, and the export is electronically signed.

#### AI / Human-in-the-Loop

- AC-01-AI-01 — Static analysis of authentication and authority module sources finds zero references to large-language-model SDKs.
- AC-01-AI-02 — When the MIRA agent queries any other module, the authentication state is not mutated.

#### Negative paths

- AC-01-NEG-01 — Given five failed login attempts within fifteen minutes, When a sixth occurs, Then 423 ACCOUNT_LOCKED with lockedUntil; an account_lockout event is logged.
- AC-01-NEG-02 — Given a payload to login containing spoofed `ip`, `userAgent`, `timestamp`, When processed, Then those values are dropped and the audit row carries server-derived values.

#### Performance

- AC-01-PERF-01 — Login p95 latency MUST be ≤ 500 milliseconds at 1 000 requests per second sustained for fifteen minutes (excluding network).
- AC-01-PERF-02 — Refresh p95 latency MUST be ≤ 200 milliseconds at 5 000 requests per second sustained for fifteen minutes.
- AC-01-PERF-03 — Authority Resolver p95 ≤ 100 milliseconds.

#### Security

- AC-01-SEC-01 — Penetration test: no SQL injection in any Module 1 endpoint.
- AC-01-SEC-02 — Penetration test: refresh-token replay produces TOKEN_REUSE_DETECTED and revokes all sessions.
- AC-01-SEC-03 — Penetration test: tenant isolation cannot be bypassed via cross-tenant token replay.

#### Migration / backfill

- AC-01-MIG-01 — Module 1 migrations are idempotent; running each twice yields no error and no schema drift.
- AC-01-MIG-02 — Applying all Module 1 migrations to a clean database produces every entity in §6.1 with Row-Level Security enabled and the canonical seed of Authority Profiles loaded.

### 16.4 Requirements ↔ test cases traceability

This map is the seed for the IQ / OQ / PQ traceability matrix. Every MUST requirement traces to at least one plain-language scenario, at least one technical test case, and one Given / When / Then summary.

| Requirement | Plain-language | Technical | Given / When / Then |
|---|---|---|---|
| URS-01-FE-001 | TC-PLAIN-001 | TC-TECH-001 | AC-01-FUN-01 |
| URS-01-FE-002 | TC-PLAIN-001, TC-PLAIN-011 | TC-TECH-002 | AC-01-FUN-02 |
| URS-01-FE-003 | TC-PLAIN-003, TC-PLAIN-007 | TC-TECH-001, TC-TECH-002, TC-TECH-004 | AC-01-FUN-01, AC-01-API-01 |
| URS-01-FE-004 | TC-PLAIN-005 | TC-TECH-014 | AC-01-NEG-02 |
| URS-01-FE-005 | TC-PLAIN-012 | TC-TECH-012, TC-TECH-023 | AC-01-UI-01 |
| URS-01-FE-006 | TC-PLAIN-005, TC-PLAIN-011 | TC-TECH-023 | AC-01-INT-01 |
| URS-01-FE-007 | TC-PLAIN-002 | TC-TECH-006 | AC-01-UI-03 |
| URS-01-FE-008 | TC-PLAIN-002 | TC-TECH-006 | AC-01-UI-03 |
| URS-01-FE-009 | — | TC-TECH-004 | — |
| URS-01-FE-010 | — | TC-TECH-022 | — |
| URS-01-FE-011 | — | TC-TECH-001 | — |
| URS-01-FE-013 | — | TC-TECH-006 | — |
| URS-01-FE-014 | — | TC-TECH-015 | AC-01-FUN-04 |
| URS-01-FE-015 | TC-PLAIN-002 | TC-TECH-006 | — |
| URS-01-FE-016 | TC-PLAIN-012 | TC-TECH-012 | — |
| URS-01-FE-017 | TC-PLAIN-005, TC-PLAIN-013 | TC-TECH-008, TC-TECH-014 | AC-01-ESIG-01, AC-01-ESIG-02 |
| URS-01-FE-018 | TC-PLAIN-005 | TC-TECH-008, TC-TECH-014 | AC-01-ESIG-01 |
| URS-01-BE-001 | TC-PLAIN-011 | TC-TECH-001 | AC-01-FUN-01 |
| URS-01-BE-002 | — | TC-TECH-001, TC-TECH-002 | — |
| URS-01-BE-003 | — | TC-TECH-004 | AC-01-API-01 |
| URS-01-BE-004 | TC-PLAIN-012 | TC-TECH-012 | AC-01-API-02 |
| URS-01-BE-005 | TC-PLAIN-003, TC-PLAIN-007 | TC-TECH-008 | AC-01-API-03 |
| URS-01-BE-006 | TC-PLAIN-011 | TC-TECH-005 | — |
| URS-01-BE-007 | TC-PLAIN-009 | TC-TECH-010 | AC-01-AUD-02 |
| URS-01-BE-008 | TC-PLAIN-003 | TC-TECH-008, TC-TECH-017 | AC-01-AUD-01 |
| URS-01-BE-009 | TC-PLAIN-004 | TC-TECH-013 | AC-01-WF-01 |
| URS-01-BE-010 | — | TC-TECH-024 | — |
| URS-01-BE-011 | TC-PLAIN-012 | TC-TECH-012, TC-TECH-025 | — |
| URS-01-BE-012 | TC-PLAIN-005 | TC-TECH-014 | AC-01-NEG-02 |
| URS-01-BE-013 | TC-PLAIN-003 | TC-TECH-008 | — |
| URS-01-BE-014 | — | TC-TECH-015 | — |
| URS-01-BE-015 | — | TC-TECH-018 | — |
| URS-01-BE-016 | TC-PLAIN-002, TC-PLAIN-010 | TC-TECH-006, TC-TECH-007 | — |
| URS-01-BE-017 | TC-PLAIN-011 | TC-TECH-005 | — |
| URS-01-BE-018 | TC-PLAIN-001 | TC-TECH-003, TC-TECH-016 | AC-01-NEG-01 |
| URS-01-BE-019 | — | TC-TECH-002, TC-TECH-003 | — |
| URS-01-BE-020 | TC-PLAIN-008 | TC-TECH-019, TC-TECH-022 | — |
| URS-01-WF-001 | TC-PLAIN-002 | TC-TECH-006, TC-TECH-007, TC-TECH-008 | — |
| URS-01-WF-002 | TC-PLAIN-003 | TC-TECH-008 | — |
| URS-01-WF-003 | TC-PLAIN-004 | TC-TECH-013 | AC-01-WF-01 |
| URS-01-WF-004 | TC-PLAIN-004 | TC-TECH-013 | — |
| URS-01-DATA-001 | — | TC-TECH-022 | — |
| URS-01-DATA-002 | TC-PLAIN-013 | TC-TECH-010, TC-TECH-011 | AC-01-DI-01 |
| URS-01-DATA-003 | TC-PLAIN-013 | TC-TECH-010, TC-TECH-011 | AC-01-DI-01 |
| URS-01-DATA-004 | TC-PLAIN-013 | TC-TECH-011 | AC-01-DI-01 |
| URS-01-DATA-005 | — | TC-TECH-022 | AC-01-DI-02 |
| URS-01-DATA-006 | TC-PLAIN-009 | TC-TECH-010 | — |
| URS-01-SEC-001 | TC-PLAIN-008 | TC-TECH-019 | AC-01-SEC-03 |
| URS-01-SEC-002 | — | TC-TECH-001 | — |
| URS-01-SEC-003 | — | (Validation evidence — KMS configuration) | — |
| URS-01-SEC-004 | — | TC-TECH-018 | — |
| URS-01-SEC-005 | — | (Penetration scan) | AC-01-SEC-01 |
| URS-01-SEC-006 | — | (Static + log scrub test) | — |
| URS-01-SEC-007 | TC-PLAIN-006 | TC-TECH-009 (system attribution) | — |
| URS-01-AUD-001 | TC-PLAIN-013 | TC-TECH-001, TC-TECH-008, TC-TECH-024 | AC-01-AUD-01 |
| URS-01-AUD-002 | TC-PLAIN-005 | TC-TECH-014 | AC-01-NEG-02 |
| URS-01-AUD-003 | TC-PLAIN-006 | TC-TECH-009 | AC-01-AUD-01 |
| URS-01-AUD-004 | — | TC-TECH-024 | — |
| URS-01-AUD-005 | TC-PLAIN-009, TC-PLAIN-013 | TC-TECH-010, TC-TECH-011 | AC-01-AUD-02, AC-01-INT-02 |
| URS-01-ESIG-001 | TC-PLAIN-005 | TC-TECH-008, TC-TECH-014 | AC-01-ESIG-01 |
| URS-01-ESIG-002 | TC-PLAIN-005 | TC-TECH-014 | AC-01-ESIG-02 |
| URS-01-ESIG-003 | — | TC-TECH-011 | — |
| URS-01-ESIG-004 | — | TC-TECH-016 (re-auth on unlock) | — |
| URS-01-AI-001 | — | (Static analysis) | AC-01-AI-01 |
| URS-01-AI-002 | — | (Integration) | AC-01-AI-02 |
| URS-01-INT-001 | TC-PLAIN-007 | TC-TECH-001 | — |
| URS-01-INT-002 | — | TC-TECH-001 | — |
| URS-01-INT-003 | TC-PLAIN-005 | TC-TECH-008 | — |
| URS-01-INT-004 | TC-PLAIN-003, TC-PLAIN-004 | TC-TECH-008, TC-TECH-013 | — |
| URS-01-INT-005 | TC-PLAIN-007 | TC-TECH-008 | — |
| URS-01-INT-006 | TC-PLAIN-001, TC-PLAIN-007, TC-PLAIN-012 | TC-TECH-012, TC-TECH-016 | — |
| URS-01-INT-007 | TC-PLAIN-013 | TC-TECH-011 | AC-01-INT-02 |
| URS-01-REP-001 | TC-PLAIN-013 | TC-TECH-011 | AC-01-REP-01 |
| URS-01-REP-002 | TC-PLAIN-013 | TC-TECH-011 | AC-01-REP-01 |
| URS-01-REP-003 | TC-PLAIN-013 | TC-TECH-011 | — |
| URS-01-VAL-001 | — | TC-TECH-022 | — |
| URS-01-VAL-002 | All applicable | All applicable | All applicable |
| URS-01-VAL-003 | All applicable | All applicable | All applicable |
| URS-01-VAL-004 | — | The full TC-TECH suite re-run on each release candidate | — |
| URS-01-VAL-005 | — | This table is the seed of the traceability matrix | — |

---

## 17. Validation Evidence Expectations (CSV / CSA)

| Item | Required evidence |
|---|---|
| URS traceability | A matrix linking every requirement identifier in §15 to one or more test-case identifiers and to a regulatory mapping row in §14. |
| Risk assessment | A GAMP 5 risk register with severity × probability × detectability for every Module 1 component; risk-based assurance level determined per FDA Computer Software Assurance. |
| Configuration specification | Documented configuration of cookies, JSON Web Token issuer, audience, algorithm, Key Management Service key references, password policy defaults, session policy defaults, lockout policy defaults, and Authority Profile seed. |
| Functional specification | Matches §6 of this document. |
| Design specification | Matches §6.1–§6.4. |
| Test protocols | Installation Qualification (schema, Row-Level Security, indexes, integrity genesis); Operational Qualification (per §15.11.URS-01-VAL-002); Performance Qualification (per §15.11.URS-01-VAL-003); regression per §15.11.URS-01-VAL-004. |
| Test evidence | Pass / fail records for every protocol step, traced to requirement identifier. |
| Defect log | Defects mapped to URS requirement identifiers; resolved before release. |
| Requirements traceability matrix | Per §16.4. |
| Release approval | Electronically signed by Quality Lead, Validation Lead, Information Security Lead, Regulatory Affairs Lead, executive authority. |
| Training record | Engineering, QA, validation, and operations trained on Module 1 expected state. |
| Supplier assessment | Identity-provider integrations assessed per GAMP 5 supplier assessment template. |
| Periodic review | Annual review of Module 1 evidence pack; trigger reviews on every significant change per EU GMP Annex 11 §11. |
| Data migration evidence | Any backfill of claims version, hash-chain genesis rows, or default Authority Profile seed. |

### 17.1 Supplier and service-provider qualification pack

Module 1 depends on external suppliers and service providers whose qualification is the regulated tenant's responsibility under EU GMP Annex 11 §3 and is expected by the FDA. The validation pack MUST include qualification evidence for each of the categories below; absence of any item is a release-blocker.

| Supplier / service-provider category | Required qualification evidence |
|---|---|
| Cloud hosting provider | Information-security certifications (ISO/IEC 27001, SOC 2 Type II), data-centre physical-security attestations, change-management evidence for the hosting platform, geographic-residency attestation matching tenant data-residency requirements, business-continuity / disaster-recovery commitments, sub-processor list. |
| Key Management Service provider | Cryptographic-module certification (FIPS 140-2 or 140-3 as applicable), key-rotation evidence, key-access logging evidence, sub-processor list, cryptographic-key custody and destruction procedures. |
| E-mail / notification delivery provider | Deliverability service-level evidence, encryption-in-transit attestation (TLS 1.2 or higher), bounce / complaint handling, sub-processor list, retention of delivery audit evidence sufficient to support the notification-related audit events of this module. |
| Single sign-on / identity-provider integration (per tenant) | Tenant-supplied identity provider qualification by the tenant; Verixa-side integration test evidence; documented behaviour under identity-provider outage; documented just-in-time provisioning rules. |
| Backup and restore provider | Backup integrity evidence, restore-drill evidence with hash-chain integrity verification (linked to URS-35), retention of backup-set audit evidence, sub-processor list. |
| Security operations centre / Security Information and Event Management | Alert-routing evidence (target audience, channel, escalation matrix), runbook for each Module-1 alert class, documented mean-time-to-acknowledge and mean-time-to-resolve targets. |
| Service-level agreement | Documented availability target, latency target (consistent with §16 performance criteria), incident-credit clauses, planned-maintenance window. |
| Incident response | Incident-response runbook, contact tree, evidence of joint tabletop exercise with Verixa engineering and the tenant's quality team at least annually. |
| Right-to-audit / inspection support | Contractual right-to-audit clause; supplier commitment to support regulator inspections of the regulated tenant; supplier-supplied inspection-pack template. |

The supplier-qualification pack is electronically signed by the QA Head and the Information Security Head and is retained for the same period as the authority change log.

### 17.2 Inspection-ready evidence index

For every requirement in §15 the validation pack MUST link a chain of evidence through the artefacts below. The index is itself a controlled artefact, electronically signed by the validation lead, retained per EU GMP Annex 11 §17.

| Stage | Artefact | Owner |
|---|---|---|
| Requirement | URS requirement identifier (§15) | Author |
| Functional specification | The functional specification clause that elaborates the URS requirement | Engineering |
| Design specification | The design specification clause that names the data model, API contract, or component | Engineering |
| Source code reference | The named module / component / migration / test file identifier | Engineering |
| Test protocol | The Installation, Operational, or Performance Qualification protocol step exercising the requirement | Validation |
| Executed evidence | The pass / fail record produced when the protocol step is executed against the released candidate | Validation |
| Deviations | Any deviation raised during execution, its disposition, and the linked CAPA if applicable | Quality Assurance |
| Release approval | The electronically signed release approval that authorised the candidate to enter production | Founder, QA, RA, Validation, Information Security |

A requirement without a complete chain in this index MUST NOT be claimed as validated.

---

## 18. Decision and Dependency Register

### 18.1 Closed Decision Register

Every closed launch decision is locked below with a binding launch decision. No Module 1 internal open questions remain. Items that remain external are tracked in §18.2 Dependencies.

| ID | Decision | Disposition |
|---|---|---|
| DEC-01-13 | **Mode A is the default and mandatory for launch.** Any regulated authority revocation or base-role downgrade revokes the session at next refresh and returns `401 SESSION_REVOKED_AUTHORITY_CHANGE`. | Locked: no alternative default. |
| DEC-01-14 | **Mode C is not enabled by default in Phase 1.** High-risk regulated routes still fail closed through the authority-check hook. Mode C may be added later only by URS-13. | Locked: post-launch change candidate. |
| DEC-01-15 | **Default lockout is five failed attempts within a fifteen-minute window producing a fifteen-minute lockout.** Tenant-configurable within validated bounds: maximum attempts three to ten; window one to sixty minutes; lockout one to one hundred and twenty minutes. | Locked. |
| DEC-01-16 | **Launch Authority Profile seed is frozen exactly as listed in §3.3.3.** Additions are Class 3 if additive. Deprecations or semantic changes are Class 1. Founder electronic signature required for global seed changes. | Locked. |
| DEC-01-17 | **Access token maximum lifetime is eight hours. Refresh token maximum lifetime is thirty days. Refresh token rotates on every use. Reuse revokes all sessions and emits `TOKEN_REUSE_DETECTED`.** | Locked. |
| DEC-01-18 | **No fixed password-expiry default is imposed by regulation across all tenants.** Default: maximum age disabled unless tenant standard operating procedure or jurisdiction requires it. If enabled, tenant configuration must define `max_age_days` and `expiry_warning_days`, with electronic signature and audit. | Locked. |
| DEC-01-19 | **Phase 1 cookie strategy: single application domain only.** Cookies are HttpOnly, Secure in production, `SameSite=Lax`; refresh cookie is path-scoped to `/auth/refresh`. Apex / cross-subdomain cookie strategy is out of Phase 1 unless required by a signed customer architecture. | Locked. |
| DEC-01-20 | **Phase 1 launch uses Verixa-managed users.** OpenID Connect and Security Assertion Markup Language remain specified but are not required for the first design-partner evidence workflow unless a signed customer requires it. Full customer single sign-on activation is conversion-stage scope. This matches the program plan's identity / single-sign-on delay mitigation. | Locked. |
| DEC-01-21 | **Hardware-token multi-factor authentication / FIDO2 / WebAuthn is out of Phase 1 and out of Module 1 launch scope.** Launch multi-factor authentication is Time-based One-Time Password plus backup codes only. | Locked: future roadmap. |
| DEC-01-22 | **Migration evidence is a release gate, not a launch-decision item.** Module 1 cannot be approved for validation execution until migrations exist and prove every §6.2 table, constraint, Row-Level Security policy, append-only log, hash-chain field, and index. Captured as URS-01-VAL-008 (Migration Evidence Gate). | Locked: mandatory Installation Qualification evidence gate. |
| DEC-01-23 | **Security Operations Centre / Security Information and Event Management alert routing is mandatory for resolver outages, chain-integrity breaks, token reuse, session hijack, audit-write failure, and every use of `global_quality_oversight`.** Until a Security Operations Centre vendor exists, route to the named Security or Chief Information Security Officer owner plus the executive authority escalation mailbox and chat channel. | Locked. |
| DEC-01-24 | **CDSCO / D&C Act applicability is conditional per tenant and product class.** Module 1 remains jurisdiction-neutral access-control infrastructure. Tenant-specific CDSCO mapping belongs in the tenant validation pack and legal-regulatory assessment, not in this URS. | Locked as tenant-specific external dependency. |
| DEC-01-25 | **External identity discriminator is fixed for launch:** `inspector`, `external_auditor`, `supplier_user`, `cro_user`, `customer_user`. External users map to `viewer` or `auditor`, never hold an Authority Profile, must have bounded access windows, and must be revocable by tenant administrator. Portal-specific lifecycle details move to the relevant portal modules. | Locked. |
| DEC-01-26 | **System identity registry is fixed for Module 1 launch:** `system@verixa.internal`, `backup-runner@verixa.internal`, `integrity-verifier@verixa.internal`, `notification-runner@verixa.internal`, `mira-agent@verixa.internal`. Additions are Class 1 controlled changes. | Locked. |
| DEC-01-15 | **Segregation-of-Duties exception governance and the `AUTHORITY_OVERRIDE_USED` event are not launch scope for Module 1.** Launch rule: Segregation-of-Duties violations are blocked, not overridden. Override capability requires URS-05 plus URS-04 controlled workflow, dual approval, electronic signature, Security Operations Centre alert, and URS-13 before activation. | Closed as post-launch controlled change. |

### 18.2 Dependencies

| Identifier | Dependency | Owner |
|---|---|---|
| DEP-01-01 | URS-02 RBAC permission catalogue and per-route permission middleware | RBAC squad |
| DEP-01-02 | URS-04 Controlled Approval Modal and electronic-signatures table | Workflow / E-signature squad |
| DEP-01-03 | URS-05 Authority Profile catalogue, segregation-of-duties rules, scope-rule registry | Authority squad |
| DEP-01-04 | URS-08 Tenant master and active / inactive status | Tenant squad |
| DEP-01-05 | URS-30 Notification delivery service | Communications squad |
| DEP-01-06 | URS-35 Backup / restore / hash-chain restore drill | Infrastructure squad |
| DEP-01-07 | URS-06 Universal audit substrate and retention | Audit squad |
| DEP-01-08 | URS-31 Document Quality Gateway handoff for documented evidence linked to authority changes | Document Quality Gateway squad |
| DEP-01-09 | URS-32 MIRA prompt envelope specification | MIRA squad |
| DEP-01-10 | Cloud Key Management Service key references for password / token / single-sign-on secret encryption | Security / Platform squad |

---

## 19. Completeness Checklist

| Item | Yes / No | Evidence |
|---|---|---|
| Front-end covered (screens, forms, state machines, UX safety) | Yes | §5 |
| Back-end covered (entities, data model, application programming interfaces, business rules) | Yes | §6 |
| Workflow covered (states, transitions, time-bounds, queues) | Yes | §5.4, §6.4, §10 |
| Data model covered | Yes | §6.2 |
| Application programming interface covered | Yes | §6.3 |
| Permissions covered | Yes | §3, §6.3 |
| Audit trail covered | Yes | §6.6, §6.6.1, BR-01-17, URS-01-AUD-001..006 |
| Electronic signature covered | Yes | §6.7, §6.7.1, URS-01-ESIG-001..006 |
| AI / Human-in-the-Loop covered | Yes (no AI; documented exclusion) | §8 |
| Reports covered | Yes | §9 |
| Notifications covered | Yes | §10 |
| Cross-module wiring covered | Yes | §7 |
| Negative paths covered | Yes | §11 |
| Regulatory mapping covered | Yes | §14 |
| Acceptance criteria covered | Yes | §16 |
| Validation evidence covered (Installation / Operational / Performance Qualification) | Yes | §17, §17.1, §17.2, URS-01-VAL-001..008 |
| ALCOA+ table populated | Yes | §13 |
| Decisions and dependencies registered (no internal decisions outstanding) | Yes | §18.1 Closed Decision Register, §18.2 Dependencies |
| Final quality gate answered | Yes | §20 |

---

## 20. Final Module Output Quality Gate

**URS approval is separate from validation execution.** This document becomes "Approved Controlled URS — released for engineering implementation and validation planning" only after signature capture in the Document Approval block. It becomes "Released for validation execution" only after the module migration evidence gate (URS-01-VAL-008) and validation evidence pack are satisfied. **No Module 1 internal open questions remain.** Remaining items are controlled cross-module dependencies tracked in §18.2 and validation-evidence gates tracked in §15.11 and §17.

- **Specification ready for engineering review?** Yes — every MUST requirement is declarative, atomic, and testable. Front end, back end, data, application programming interface, workflow, audit, electronic signature, security, and integration are covered as a single self-contained contract.
- **Specification ready for quality validation review?** Yes — Installation, Operational, and Performance Qualification scope is specified; the traceability matrix template is defined in §16.4.
- **Specification ready for compliance review?** Yes — the ALCOA+ table, the regulatory mapping, the predicate-rule applicability matrix in §14.1, the periodic access review and audit-trail review controls in §12.10–§12.11, and the electronic-signature certification and accountability controls in §6.7.1 are populated.
- **Specification ready for inspector or client review?** Yes — every regulated assertion traces to a regulatory clause and to a test case; no internal item remains open. The document becomes an approved validation baseline upon signature capture in the Document Approval block plus completion of the Installation Qualification gate (URS-01-VAL-008) and the validation evidence pack (§17).
- **Specification ready for Founder approval?** Yes.
- **Blocking gaps?** **None internal.** All Module 1 launch decisions are captured in §18.1 (Closed Decision Register). The remaining items are not Module 1 blockers: (a) the cross-module dependencies in §18.2 are owned by their named companion modules (URS-02 RBAC, URS-04 Workflow / E-Sign, URS-05 Authority, URS-06 Audit, URS-08 Tenant, URS-30 Notifications, URS-31 DQG, URS-32 MIRA, URS-35 Backup / Restore) and are tracked at the program level; (b) the Installation Qualification gate URS-01-VAL-008 (Migration Evidence Gate) and the validation evidence pack in §17 are release-time gates and are tracked by the validation lead. Their availability conditions end-to-end execution and Approved-Controlled-URS issuance, but does not block approval of Module 1 as a controlled specification.
- **Two-step release path:**
  1. **Approved Controlled URS — released for engineering implementation and validation planning.** Reached upon signature capture in the Document Approval block.
  2. **Released for validation execution.** Reached after URS-01-VAL-008 (Migration Evidence Gate) and the §17 evidence pack are satisfied.

---

## Appendix A — Bootstrap and Refresh Lifecycle

```mermaid
flowchart TD
  A([Browser opens application]) --> B[Application root mounts]
  B --> C[useMe → GET /auth/me]
  C --> D{200 OK?}
  D -- Yes --> E[setAuthState atomic<br/>user + csrfToken + authzContext]
  E --> F[Application renders authenticated routes]
  F --> G[Each request: API client injects X-CSRF-Token]
  G --> H{Access cookie expired?}
  H -- Yes --> I[Interceptor calls /auth/refresh once]
  I --> J{Refresh OK?}
  J -- Yes --> K[Update store; retry original request]
  K --> G
  J -- No 401 --> L[Clear store; redirect /auth/login?returnTo]
  H -- No --> G
  D -- 401 --> L
  D -- 503 AUTHZ_CONTEXT_RESOLUTION_FAILED --> M[Render persistent banner;<br/>disable AuthorityGuard buttons;<br/>poll /auth/me until recovered]
  M --> F
```

— End of Module 1 User Requirements Specification —
