Skip to main content

Work Order System — Electronic Signature Architecture

Classification: Internal — Compliance Engineering Date: 2026-02-13 Status: Proposed Regulatory Mapping: FDA 21 CFR Part 11 §11.50, §11.70, §11.100, §11.200


1. Regulatory Requirements Mapping

1.1 Part 11 Subpart C — Electronic Signatures

SectionRequirementImplementation
§11.50Signature manifestations: signed name, date/time, meaningElectronicSignature.signerId → Person.name, .signedAt, .meaning
§11.70Signature/record linking: signatures bound to their respective recordsApproval.signatureId FK → ElectronicSignature.id, immutable after creation
§11.100General requirements: each signature unique to one individual, verified identity before establishmentPerson.email unique per tenant, identity verification via IdP/SSO, signature cannot be reused across approvals
§11.200Electronic signature components: at least two distinct identification components (e.g., ID + password)ElectronicSignature.authMethod captures authentication context; re-authentication required for each signing event

1.2 Part 11 Subpart B — Electronic Records

SectionRequirementImplementation
§11.10(a)Validation of systemsCODITECT platform IQ/OQ/PQ documentation
§11.10(b)Generate accurate and complete copiesAudit trail export with full signature chain
§11.10(c)Protection of records throughout retention periodPostgreSQL with encrypted storage, backup policy
§11.10(e)Audit trail: computer-generated, stamped, independent of operatorAuditTrail table with DB trigger preventing modification
§11.10(g)Authority checks: only authorized individuals can use systemRBAC enforcement at API gateway + state machine guards
§11.10(k)Controls for systems documentationVersion-controlled schema migrations

2. Signature Flow Architecture

2.1 Sequence Diagram

User                    Frontend            API Gateway          WO Service           Signature Service    PostgreSQL
│ │ │ │ │ │
│ Click "Approve WO" │ │ │ │ │
│───────────────────────>│ │ │ │ │
│ │ │ │ │ │
│ Re-authentication │ │ │ │ │
│ Dialog (password or │ │ │ │ │
│ SSO re-auth prompt) │ │ │ │ │
│<───────────────────────│ │ │ │ │
│ │ │ │ │ │
│ Enter credentials │ │ │ │ │
│───────────────────────>│ │ │ │ │
│ │ POST /signatures │ │ │ │
│ │ {signerId, │ │ │ │
│ │ meaning, │ │ │ │
│ │ authContext} │ │ │ │
│ │───────────────────>│ │ │ │
│ │ │ Validate AuthN │ │ │
│ │ │ + RBAC │ │ │
│ │ │──────────────────>│ │ │
│ │ │ │ Create signature │ │
│ │ │ │──────────────────>│ │
│ │ │ │ │ BEGIN TX │
│ │ │ │ │──────────────────>│
│ │ │ │ │ INSERT signature │
│ │ │ │ │──────────────────>│
│ │ │ │ │ signatureId │
│ │ │ │ │<──────────────────│
│ │ │ │ signatureId │ │
│ │ │ │<──────────────────│ │
│ │ signatureId │ │ │ │
│ │<───────────────────│ │ │ │
│ │ │ │ │ │
│ │ POST /work-orders/{id}/approvals │ │ │
│ │ {role, decision, │ │ │ │
│ │ comment, │ │ │ │
│ │ signatureId} │ │ │ │
│ │───────────────────>│ │ │ │
│ │ │──────────────────>│ │ │
│ │ │ │ Verify: │ │
│ │ │ │ 1. sig.signerId │ │
│ │ │ │ == approverId │ │
│ │ │ │ 2. sig is recent │ │
│ │ │ │ (<5 min) │ │
│ │ │ │ 3. sig not used │ │
│ │ │ │ 4. user has role │ │
│ │ │ │──────────────────────────────────────>│
│ │ │ │ INSERT approval │ │
│ │ │ │ INSERT audit │ │
│ │ │ │ UPDATE wo status │ │
│ │ │ │ COMMIT TX │ │
│ │ │ │<──────────────────────────────────────│
│ │ 200 OK │ │ │ │
│ │<───────────────────│ │ │ │
│ Approval confirmed │ │ │ │ │
│<───────────────────────│ │ │ │ │

2.2 Two-Phase Commit Pattern

The signature flow uses a two-phase pattern to maintain separation of concerns:

Phase 1: Create Signature — Captures identity assertion independent of what is being signed. This mirrors how physical signatures work: the act of signing is separate from what's on the document.

Phase 2: Bind Signature to Action — Associates the signature with a specific approval record on a specific work order. The binding is validated server-side to prevent signature reuse.

This separation enables:

  • Signature reuse prevention (each signature ID used exactly once)
  • Time-window enforcement (signature must be used within 5 minutes)
  • Clear audit trail (signature event and approval event logged separately)
  • Support for multi-signature workflows (System Owner + QA on regulatory WOs)

3. Data Model

3.1 ElectronicSignature Entity

interface ElectronicSignature {
id: string; // cuid, immutable
tenantId: string; // RLS partition key
signerId: string; // FK → Person.id (unique individual)
meaning: string; // Human-readable: "Approval of Work Order WO-2026-001"
signedAt: Date; // Server-generated, not client-supplied
reason: string | null; // Optional: why this signature was applied
authMethod: AuthMethod; // How identity was verified
sessionId: string | null; // IdP session identifier
ipAddress: string | null; // Client IP for forensics
consumed: boolean; // True after binding to an approval
consumedAt: Date | null; // When the signature was consumed
consumedBy: string | null; // Which approval consumed it
}

type AuthMethod =
| 'password' // Username + password re-entry
| 'smartcard' // PKI smart card
| 'sso_reauth' // SSO provider re-authentication
| 'biometric' // Fingerprint, face
| 'totp' // Time-based OTP
;

3.2 Approval Entity (Extended)

interface Approval {
id: string;
tenantId: string;
workOrderId: string;
role: 'SYSTEM_OWNER' | 'QA' | 'OTHER';
approverId: string; // FK → Person.id (MUST be human)
decision: 'APPROVED' | 'REJECTED';
decisionTs: Date;
comment: string | null;
signatureId: string; // FK → ElectronicSignature.id (required for Part 11)

// Part 11 manifestation fields (denormalized for report generation)
signerName: string; // Snapshot of Person.name at signing time
signatureMeaning: string; // Copy of signature.meaning
}

3.3 Validation Rules

async function validateSignatureBinding(
signature: ElectronicSignature,
approval: { approverId: string; workOrderId: string }
): Promise<ValidationResult> {
const errors: string[] = [];

// Rule 1: Signer must match approver
if (signature.signerId !== approval.approverId) {
errors.push('Signature signer does not match approver identity');
}

// Rule 2: Signature must be recent (5-minute window)
const ageMs = Date.now() - signature.signedAt.getTime();
if (ageMs > 5 * 60 * 1000) {
errors.push(`Signature expired: ${Math.round(ageMs / 1000)}s old, max 300s`);
}

// Rule 3: Signature not already consumed
if (signature.consumed) {
errors.push(`Signature already consumed by approval ${signature.consumedBy}`);
}

// Rule 4: Signature tenant matches approval tenant
// (Enforced by RLS, but belt-and-suspenders)

return {
valid: errors.length === 0,
errors
};
}

4. Multi-Signature Workflows

4.1 Regulatory Work Order Approval Chain

Regulatory WOs (regulatoryFlag=true) require a two-signature approval:

                    ┌─────────────────────┐
│ PENDING_REVIEW │
└─────────┬───────────┘

┌─────────▼───────────┐
│ System Owner │
│ Approval Required │
│ ┌──────────────┐ │
│ │ e-Signature │ │
│ │ Phase 1 + 2 │ │
│ └──────────────┘ │
└─────────┬───────────┘

┌─────────▼───────────┐
│ QA Approval │
│ Required │
│ ┌──────────────┐ │
│ │ e-Signature │ │
│ │ Phase 1 + 2 │ │
│ └──────────────┘ │
└─────────┬───────────┘

┌─────────▼───────────┐
│ APPROVED │
└─────────────────────┘

4.2 Non-Regulatory Approval Chain

Non-regulatory WOs require only System Owner approval:

PENDING_REVIEW → System Owner e-Signature → APPROVED

4.3 Guard Logic

function getRequiredApprovals(wo: WorkOrder): ApprovalRequirement[] {
const required: ApprovalRequirement[] = [
{ role: 'SYSTEM_OWNER', signatureRequired: true }
];

if (wo.regulatoryFlag) {
required.push({ role: 'QA', signatureRequired: true });
}

// Tenant-configurable additional approvers
const tenantConfig = getTenantApprovalConfig(wo.tenantId);
if (tenantConfig.additionalApprovers) {
required.push(...tenantConfig.additionalApprovers);
}

return required;
}

function canTransitionToApproved(wo: WorkOrder, approvals: Approval[]): boolean {
const required = getRequiredApprovals(wo);

return required.every(req =>
approvals.some(a =>
a.role === req.role &&
a.decision === 'APPROVED' &&
(!req.signatureRequired || a.signatureId != null)
)
);
}

5. Agent-Delegated Signatures

5.1 The Problem

CODITECT agents (QAReviewNode, WorkOrderOrchestratorNode) may need to process approvals, but Part 11 requires signatures from identified individuals. Agents cannot sign.

5.2 Solution: Pre-Authorized Delegation

Human QA Officer                     QA Review Agent
│ │
│ Pre-authorize: "Approve WO-001 │
│ if all validation artifacts present │
│ and no critical findings" │
│─────────────────────────────────────>│
│ │
│ e-Sign delegation authorization │
│ (Phase 1 signature on the │
│ delegation intent) │
│─────────────────────────────────────>│
│ │
│ Agent verifies conditions:
│ ✓ IQ/OQ docs attached
│ ✓ No critical findings
│ ✓ All child WOs complete
│ │
│ Agent creates approval:
│ approverId = QA Officer
│ signatureId = delegation sig
│ performerType = AGENT
│ agentSessionId = trace-123
│ │
│ Notification: WO-001 approved │
│ on your behalf by QA Review Agent │
│<─────────────────────────────────────│

5.3 Delegation Constraints

ConstraintValueRationale
Delegation TTL24 hours maxPrevent stale authorizations
ScopeSingle WO or WO batchNo blanket delegations
ConditionsMust be machine-verifiableAgent can't interpret subjective criteria
NotificationMandatory post-actionHuman must be informed of agent actions
RevocationImmediate, any timeHuman can cancel delegation
AuditFull chain recordedDelegation → conditions check → approval logged

6. API Endpoints

6.1 Signature Lifecycle

POST /api/v1/signatures
Request:
signerId: string # Must match authenticated user
meaning: string # "Approval of Work Order {woId}"
reason?: string
authContext:
method: string # "password" | "sso_reauth" | ...
sessionId?: string
Response: 201
id: string
signedAt: string (ISO 8601)
consumed: false

GET /api/v1/signatures/{id}
Response: 200
# Full signature record

POST /api/v1/signatures/{id}/verify
# Internal endpoint for binding validation
Request:
expectedSignerId: string
maxAgeSeconds?: number # Default 300
Response: 200
valid: boolean
errors?: string[]

6.2 Approval with Signature

POST /api/v1/work-orders/{woId}/approvals
Request:
role: "SYSTEM_OWNER" | "QA" | "OTHER"
decision: "APPROVED" | "REJECTED"
comment?: string
signatureId: string # Required for Part 11 transitions
Response: 201
id: string
# Approval record with denormalized signature manifestation

GET /api/v1/work-orders/{woId}/approval-status
Response: 200
required: ApprovalRequirement[]
received: Approval[]
complete: boolean # All required approvals received
canTransition: boolean

7. Audit Trail Integration

Every signature and approval operation generates audit events:

ActionEntity TypeCaptured Data
SIGNATURE_CREATEDSIGNATUREsignerId, meaning, authMethod
SIGNATURE_CONSUMEDSIGNATUREconsumedBy (approval ID)
SIGNATURE_EXPIREDSIGNATUREexpiration reason
APPROVAL_CREATEDAPPROVALrole, decision, signatureId
APPROVAL_REJECTEDAPPROVALrole, reason, signatureId
DELEGATION_CREATEDDELEGATIONdelegator, agent, conditions, TTL
DELEGATION_EXERCISEDDELEGATIONconditions verified, approval created
DELEGATION_REVOKEDDELEGATIONrevoked by, reason

All events include: tenantId, performedBy, performerType, agentSessionId (if agent), correlationId, performedAt (server timestamp).


8. CODITECT Platform Integration

8.1 Compliance Engine Interception

The CODITECT Compliance Engine intercepts all signature and approval operations:

// Compliance Engine middleware
async function complianceGate(
operation: 'CREATE_SIGNATURE' | 'CREATE_APPROVAL' | 'TRANSITION',
context: OperationContext
): Promise<ComplianceResult> {

// Check 1: Is the signer/approver authorized for this tenant?
await verifyTenantAuthorization(context);

// Check 2: Does the WO's compliance class require additional controls?
if (context.wo.complianceClass === 'FDA_21CFR11') {
await enforcePart11Controls(context);
}

// Check 3: Log to immutable audit trail
await writeAuditEvent(context);

// Check 4: Emit compliance event to Event Bus
await emitComplianceEvent(context);

return { allowed: true };
}

8.2 Event Bus Events

// NATS topics for signature/approval events
const topics = {
signatureCreated: 'wo.compliance.signature.created',
signatureConsumed: 'wo.compliance.signature.consumed',
approvalCreated: 'wo.compliance.approval.created',
approvalChainComplete: 'wo.compliance.approval.chain_complete',
delegationCreated: 'wo.compliance.delegation.created',
delegationExercised: 'wo.compliance.delegation.exercised',
};

8.3 Observability

# Prometheus metrics for signature operations
wo_signature_created_total:
labels: [tenant_id, auth_method]
wo_signature_consumed_total:
labels: [tenant_id]
wo_signature_expired_total:
labels: [tenant_id, reason]
wo_approval_decision_total:
labels: [tenant_id, role, decision]
wo_approval_chain_duration_seconds:
labels: [tenant_id, regulatory_flag]
# Histogram: time from first approval to chain completion
wo_delegation_exercised_total:
labels: [tenant_id, agent_type]

Copyright 2026 AZ1.AI Inc. All rights reserved. Developer: Hal Casteel, CEO/CTO Product: CODITECT-BIO-QMS | Part of the CODITECT Product Suite Classification: Internal - Confidential