FDA 21 CFR Part 11 合規¶
FDA 21 CFR Part 11 規範製藥、生技、醫療器材等受管制產業的電子記錄(Electronic Records)與電子簽章(Electronic Signatures)的合規要求。NextPDF Enterprise 在 PDF 生成層直接實施這些要求,確保每份文件天生具備可舉證的合規性。
法規要求對應¶
| 21 CFR Part 11 條款 | 要求 | NextPDF Enterprise 實現 |
|---|---|---|
| § 11.10(a) | 系統驗證 | 確定性文件生成、內容雜湊驗證 |
| § 11.10(b) | 準確可讀副本 | PDF/A-4 符合性(不可變格式) |
| § 11.10(c) | 記錄保護 | WORM 模式、不可修改封存 |
| § 11.10(d) | 稽核追蹤 | FdaAuditTrail — 不可刪除時間序列日誌 |
| § 11.10(e) | 使用者存取控制 | CompliancePolicy 強制身份驗證 |
| § 11.50 | 簽章關聯 | 簽章與簽署者、時間、含義不可分離 |
| § 11.70 | 簽章與記錄連結 | 數位簽章嵌入 PDF 本體,非附加 |
| § 11.100 | 簽署者身份唯一性 | 每位簽署者使用唯一憑證 |
核心 API¶
FdaAuditTrail¶
稽核追蹤是 21 CFR Part 11 § 11.10(d) 的核心要求,必須記錄所有建立、修改、刪除操作,且日誌本身不可被修改或刪除。
use NextPDF\Enterprise\Compliance\Fda\FdaAuditTrail;
use NextPDF\Enterprise\Compliance\Fda\AuditEntry;
$auditTrail = FdaAuditTrail::create(
storageAdapter: $immutableStorageAdapter,
hashAlgorithm: 'SHA-384',
requireTimestamp: true,
);
// 每次文件操作自動記錄
$auditTrail->record(
AuditEntry::documentCreated(
documentId: $doc->id(),
userId: $currentUser->id(),
userName: $currentUser->fullName(),
timestamp: new DateTimeImmutable(),
ipAddress: $request->ip(),
action: 'DOCUMENT_CREATED',
reason: 'New batch record for Lot #2025-A-001',
)
);
PHP Compatibility
This example uses PHP 8.5 syntax. If your environment runs PHP 8.1 or 7.4, use NextPDF Backport for a backward-compatible build.
SignatureEnforcer¶
use NextPDF\Enterprise\Compliance\Fda\SignatureEnforcer;
use NextPDF\Enterprise\Compliance\Fda\CompliancePolicy;
use NextPDF\Enterprise\Compliance\Fda\ElectronicSignature;
$policy = CompliancePolicy::fda21CfrPart11(
requireElectronicSignature: true,
requireSignatureReason: true,
requireSignatureTimestamp: true,
auditTrailRetentionYears: 7,
enforceUserAuthentication: true,
allowedSignatureAlgorithms: ['RSA-PSS-SHA384', 'ECDSA-P384'],
);
$enforcer = new SignatureEnforcer(
policy: $policy,
auditTrail: $auditTrail,
);
$signature = ElectronicSignature::create(
signerCredential: $pkcs12Credential,
reason: '批准:批次放行記錄',
location: 'Quality Control Lab, Taipei',
contactInfo: 'qa@acmepharma.com',
);
$signedDocument = $enforcer->sign(
document: $document,
signature: $signature,
signerIdentity: $currentUser,
);
CompliancePolicy¶
use NextPDF\Enterprise\Compliance\Fda\CompliancePolicy;
// 工廠方法涵蓋最常見的合規情境
$policy = CompliancePolicy::fda21CfrPart11(/* ... */);
$policy = CompliancePolicy::gmpBatchRecord(/* ... */);
$policy = CompliancePolicy::clinicalTrialRecord(/* ... */);
// 或完全自定義
$policy = CompliancePolicy::custom()
->requireSignature()
->requireAuditTrail(retentionYears: 7)
->enforceTimestampAuthority('https://tsa.acmepharma.com')
->prohibitModificationAfterSignature();
文件生命週期¶
flowchart LR
A[草稿建立] -->|AuditEntry: CREATED| B[內容填寫]
B -->|AuditEntry: MODIFIED| C[審核中]
C -->|AuditEntry: REVIEWED| D{需要修改?}
D -->|是| E[退回修改]
E -->|AuditEntry: RETURNED| B
D -->|否| F[電子簽章]
F -->|AuditEntry: SIGNED| G[封存鎖定]
G -->|WORM 保存 7年| H[到期歸檔] 驗證:批次放行記錄¶
以下展示完整的 GMP 批次放行記錄合規流程:
use NextPDF\Enterprise\Compliance\Fda\FdaComplianceBundle;
// FdaComplianceBundle 整合所有 FDA 合規元件
$bundle = FdaComplianceBundle::create(
policy: CompliancePolicy::gmpBatchRecord(retentionYears: 7),
auditStorage: $wormStorageAdapter,
tsaUrl: 'https://tsa.acmepharma.com',
);
$batchRecord = $bundle->createDocument(
template: BatchRecordTemplate::lot(lotNumber: '2025-A-001'),
author: $currentUser,
);
// 填寫數據後強制簽章
$batchRecord = $bundle->signAndLock(
document: $batchRecord,
signer: $qaManagerCredential,
reason: '批次合格,授權放行',
);
// 自動封存至不可變存儲
$archiveRef = $bundle->archive($batchRecord);
常見合規陷阱¶
| 陷阱 | 風險 | NextPDF Enterprise 防護 |
|---|---|---|
| 簽章後仍可修改文件 | FDA 483 觀察 | 簽署後自動鎖定,修改嘗試拋出 PolicyViolationException |
| 稽核日誌可被刪除 | Warning Letter | FdaAuditTrail 使用不可變儲存介面,拒絕刪除操作 |
| 時間戳記由用戶端產生 | 不可信時間 | 強制使用外部 TSA(RFC 3161) |
| 缺少簽署原因欄位 | 不符 § 11.50 | CompliancePolicy 強制要求 reason 欄位非空 |
| 多人共用簽署帳號 | 不符 § 11.100 | 每個簽章對應唯一憑證,CN 綁定驗證 |