Consolidate webapp structure by merging nested components into the main repository
This commit is contained in:
600
docs/Compliance_Integration_Spec.md
Normal file
600
docs/Compliance_Integration_Spec.md
Normal file
@@ -0,0 +1,600 @@
|
||||
# Compliance Integration Specification
|
||||
|
||||
## Overview
|
||||
This document specifies compliance integration requirements for the ISO-20022 Combo Flow system, including LEI/DID/KYC/AML injection into ISO messages, compliance engine API contract, real-time status checks, identity assertion format, and audit trail requirements for hybrid workflows.
|
||||
|
||||
---
|
||||
|
||||
## 1. Compliance Requirements
|
||||
|
||||
### Required Compliance Attributes
|
||||
|
||||
| Attribute | Required For | Description | Format |
|
||||
|-----------|-------------|-------------|--------|
|
||||
| **LEI** | All workflows | Legal Entity Identifier | 20-character alphanumeric (e.g., `5493000IBP32UQZ0KL24`) |
|
||||
| **DID** | Notarized workflows | Decentralized Identifier | W3C DID format (e.g., `did:web:example.com:user:123`) |
|
||||
| **KYC** | Fiat/DTL steps | Know Your Customer verification | Level 1-3 (Level 2+ for fiat) |
|
||||
| **AML** | Payments > threshold | Anti-Money Laundering check | Pass/Fail with risk level |
|
||||
|
||||
### Compliance Levels by Workflow Type
|
||||
|
||||
#### DeFi-Only Workflows
|
||||
- **LEI**: Optional (recommended)
|
||||
- **DID**: Optional
|
||||
- **KYC**: Not required
|
||||
- **AML**: Not required
|
||||
|
||||
#### Hybrid Workflows (DeFi + Fiat/DTL)
|
||||
- **LEI**: Required
|
||||
- **DID**: Required for notarization
|
||||
- **KYC**: Level 2+ required
|
||||
- **AML**: Required for payments > 10,000 EUR
|
||||
|
||||
#### Fiat-Only Workflows
|
||||
- **LEI**: Required
|
||||
- **DID**: Required
|
||||
- **KYC**: Level 2+ required
|
||||
- **AML**: Required for all payments
|
||||
|
||||
---
|
||||
|
||||
## 2. Compliance Engine API Contract
|
||||
|
||||
### Interface: `IComplianceEngine`
|
||||
|
||||
```typescript
|
||||
interface IComplianceEngine {
|
||||
/**
|
||||
* Check compliance status for a user
|
||||
*/
|
||||
getComplianceStatus(userId: string): Promise<ComplianceStatus>;
|
||||
|
||||
/**
|
||||
* Validate compliance for a workflow
|
||||
*/
|
||||
validateWorkflowCompliance(workflow: Workflow): Promise<ComplianceCheckResult>;
|
||||
|
||||
/**
|
||||
* Run KYC verification
|
||||
*/
|
||||
verifyKYC(userId: string, level: number): Promise<KYCResult>;
|
||||
|
||||
/**
|
||||
* Run AML screening
|
||||
*/
|
||||
screenAML(userId: string, amount: number, currency: string): Promise<AMLResult>;
|
||||
|
||||
/**
|
||||
* Register LEI for user
|
||||
*/
|
||||
registerLEI(userId: string, lei: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Register DID for user
|
||||
*/
|
||||
registerDID(userId: string, did: string): Promise<boolean>;
|
||||
}
|
||||
```
|
||||
|
||||
### Compliance Status Response
|
||||
|
||||
```typescript
|
||||
interface ComplianceStatus {
|
||||
userId: string;
|
||||
lei: string | null;
|
||||
did: string | null;
|
||||
kyc: {
|
||||
level: number;
|
||||
provider: string;
|
||||
verified: boolean;
|
||||
expiresAt: string | null;
|
||||
};
|
||||
aml: {
|
||||
passed: boolean;
|
||||
provider: string;
|
||||
lastCheck: string;
|
||||
riskLevel: 'LOW' | 'MEDIUM' | 'HIGH';
|
||||
};
|
||||
valid: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Workflow Compliance Check
|
||||
|
||||
```typescript
|
||||
interface ComplianceCheckResult {
|
||||
valid: boolean;
|
||||
required: string[]; // ['LEI', 'DID', 'KYC', 'AML']
|
||||
missing: string[];
|
||||
warnings: string[];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. LEI/DID/KYC/AML Injection into ISO Messages
|
||||
|
||||
### ISO-20022 Message Structure with Compliance
|
||||
|
||||
#### pacs.008 (Payment Instruction) Example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.10">
|
||||
<FIToFICstmrCdtTrf>
|
||||
<GrpHdr>
|
||||
<MsgId>MSG-2025-01-15-001</MsgId>
|
||||
<CreDtTm>2025-01-15T10:30:00Z</CreDtTm>
|
||||
<NbOfTxs>1</NbOfTxs>
|
||||
<CtrlSum>78000.00</CtrlSum>
|
||||
<InitgPty>
|
||||
<Nm>Example Corp Ltd.</Nm>
|
||||
<Id>
|
||||
<OrgId>
|
||||
<Othr>
|
||||
<Id>5493000IBP32UQZ0KL24</Id>
|
||||
<SchmeNm>
|
||||
<Cd>LEI</Cd>
|
||||
</SchmeNm>
|
||||
</Othr>
|
||||
</OrgId>
|
||||
</Id>
|
||||
</InitgPty>
|
||||
</GrpHdr>
|
||||
<CdtTrfTxInf>
|
||||
<PmtId>
|
||||
<EndToEndId>PLAN-12345678-ABCD-EFGH</EndToEndId>
|
||||
<TxId>TX-2025-01-15-001</TxId>
|
||||
</PmtId>
|
||||
<PmtTpInf>
|
||||
<SvcLvl>
|
||||
<Cd>SEPA</Cd>
|
||||
</SvcLvl>
|
||||
<LclInstrm>
|
||||
<Cd>INST</Cd>
|
||||
</LclInstrm>
|
||||
</PmtTpInf>
|
||||
<IntrBkSttlmAmt Ccy="EUR">78000.00</IntrBkSttlmAmt>
|
||||
<InstgAgt>
|
||||
<FinInstnId>
|
||||
<BICFI>BANKDEFFXXX</BICFI>
|
||||
</FinInstnId>
|
||||
</InstgAgt>
|
||||
<InstdAgt>
|
||||
<FinInstnId>
|
||||
<BICFI>BENEFRPPXXX</BICFI>
|
||||
</FinInstnId>
|
||||
</InstdAgt>
|
||||
<Dbtr>
|
||||
<Nm>Example Corp Ltd.</Nm>
|
||||
<Id>
|
||||
<OrgId>
|
||||
<Othr>
|
||||
<Id>5493000IBP32UQZ0KL24</Id>
|
||||
<SchmeNm>
|
||||
<Cd>LEI</Cd>
|
||||
</SchmeNm>
|
||||
</Othr>
|
||||
</OrgId>
|
||||
</Id>
|
||||
<CtctDtls>
|
||||
<Email>compliance@example.com</Email>
|
||||
</CtctDtls>
|
||||
</Dbtr>
|
||||
<DbtrAcct>
|
||||
<Id>
|
||||
<IBAN>DE89370400440532013000</IBAN>
|
||||
</Id>
|
||||
</DbtrAcct>
|
||||
<Cdtr>
|
||||
<Nm>Beneficiary Corp</Nm>
|
||||
<PstlAdr>
|
||||
<StrtNm>Main Street</StrtNm>
|
||||
<BldgNb>123</BldgNb>
|
||||
<PstCd>12345</PstCd>
|
||||
<TwnNm>Berlin</TwnNm>
|
||||
<Ctry>DE</Ctry>
|
||||
</PstlAdr>
|
||||
</Cdtr>
|
||||
<CdtrAcct>
|
||||
<Id>
|
||||
<IBAN>DE89370400440532013001</IBAN>
|
||||
</Id>
|
||||
</CdtrAcct>
|
||||
<RmtInf>
|
||||
<Ustrd>Plan ID: PLAN-12345678-ABCD-EFGH</Ustrd>
|
||||
<Strd>
|
||||
<RfrdDocInf>
|
||||
<Tp>
|
||||
<CdOrPrtry>
|
||||
<Cd>CINV</Cd>
|
||||
</CdOrPrtry>
|
||||
</Tp>
|
||||
<Nb>PLAN-12345678-ABCD-EFGH</Nb>
|
||||
<RltdDt>2025-01-15</RltdDt>
|
||||
</RfrdDocInf>
|
||||
<RfrdDocAmt>
|
||||
<DuePyblAmt Ccy="EUR">78000.00</DuePyblAmt>
|
||||
</RfrdDocAmt>
|
||||
</Strd>
|
||||
</RmtInf>
|
||||
<SplmtryData>
|
||||
<PlcAndNm>ComplianceData</PlcAndNm>
|
||||
<Envlp>
|
||||
<ComplianceData xmlns="urn:example:compliance:xsd:1.0">
|
||||
<PlanId>PLAN-12345678-ABCD-EFGH</PlanId>
|
||||
<LEI>5493000IBP32UQZ0KL24</LEI>
|
||||
<DID>did:web:example.com:user:123</DID>
|
||||
<KYC>
|
||||
<Level>2</Level>
|
||||
<Provider>Onfido</Provider>
|
||||
<Verified>true</Verified>
|
||||
<ExpiresAt>2026-12-31T23:59:59Z</ExpiresAt>
|
||||
</KYC>
|
||||
<AML>
|
||||
<Passed>true</Passed>
|
||||
<Provider>Chainalysis</Provider>
|
||||
<LastCheck>2025-01-15T09:00:00Z</LastCheck>
|
||||
<RiskLevel>LOW</RiskLevel>
|
||||
</AML>
|
||||
<DigitalSignature>
|
||||
<Algorithm>ECDSA</Algorithm>
|
||||
<Value>0x1234567890abcdef...</Value>
|
||||
</DigitalSignature>
|
||||
</ComplianceData>
|
||||
</Envlp>
|
||||
</SplmtryData>
|
||||
</CdtTrfTxInf>
|
||||
</FIToFICstmrCdtTrf>
|
||||
</Document>
|
||||
```
|
||||
|
||||
### Key Compliance Injection Points
|
||||
|
||||
1. **Header (`GrpHdr.InitgPty`)**: LEI in `Id.OrgId.Othr.Id` with `SchmeNm.Cd = "LEI"`
|
||||
2. **Debtor (`Dbtr`)**: LEI in `Id.OrgId.Othr.Id`
|
||||
3. **Supplementary Data (`SplmtryData`)**: Full compliance data (LEI, DID, KYC, AML, signature)
|
||||
|
||||
---
|
||||
|
||||
## 4. Real-Time Status Checks
|
||||
|
||||
### API Endpoint: `GET /api/compliance/status`
|
||||
|
||||
```typescript
|
||||
// Request
|
||||
GET /api/compliance/status?userId=user123
|
||||
|
||||
// Response
|
||||
{
|
||||
"userId": "user123",
|
||||
"lei": "5493000IBP32UQZ0KL24",
|
||||
"did": "did:web:example.com:user:123",
|
||||
"kyc": {
|
||||
"level": 2,
|
||||
"provider": "Onfido",
|
||||
"verified": true,
|
||||
"expiresAt": "2026-12-31T23:59:59Z"
|
||||
},
|
||||
"aml": {
|
||||
"passed": true,
|
||||
"provider": "Chainalysis",
|
||||
"lastCheck": "2025-01-15T09:00:00Z",
|
||||
"riskLevel": "LOW"
|
||||
},
|
||||
"valid": true
|
||||
}
|
||||
```
|
||||
|
||||
### Workflow Compliance Check: `POST /api/compliance/check`
|
||||
|
||||
```typescript
|
||||
// Request
|
||||
POST /api/compliance/check
|
||||
{
|
||||
"steps": [
|
||||
{ "type": "borrow", "asset": "CBDC_USD", "amount": 100000 },
|
||||
{ "type": "swap", "from": "CBDC_USD", "to": "CBDC_EUR", "amount": 100000 },
|
||||
{ "type": "pay", "asset": "EUR", "amount": 78000, "beneficiary": { "IBAN": "DE89..." } }
|
||||
]
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"valid": true,
|
||||
"required": ["LEI", "DID", "KYC", "AML"],
|
||||
"missing": [],
|
||||
"warnings": []
|
||||
}
|
||||
```
|
||||
|
||||
### Frontend Integration
|
||||
|
||||
```typescript
|
||||
// Real-time compliance badge in UI
|
||||
const ComplianceBadge = () => {
|
||||
const { data: compliance } = useQuery(['compliance'], () =>
|
||||
api.getComplianceStatus()
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
{compliance?.lei && <Badge>✓ LEI</Badge>}
|
||||
{compliance?.did && <Badge>✓ DID</Badge>}
|
||||
{compliance?.kyc?.verified && <Badge>✓ KYC</Badge>}
|
||||
{compliance?.aml?.passed && <Badge>✓ AML</Badge>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Identity Assertion Format
|
||||
|
||||
### W3C Verifiable Credential Format
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://www.w3.org/2018/credentials/examples/v1"
|
||||
],
|
||||
"id": "https://example.com/credentials/123",
|
||||
"type": ["VerifiableCredential", "ComplianceCredential"],
|
||||
"issuer": {
|
||||
"id": "did:web:example.com:issuer",
|
||||
"name": "Compliance Authority"
|
||||
},
|
||||
"issuanceDate": "2025-01-15T10:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "did:web:example.com:user:123",
|
||||
"lei": "5493000IBP32UQZ0KL24",
|
||||
"kyc": {
|
||||
"level": 2,
|
||||
"provider": "Onfido",
|
||||
"verified": true,
|
||||
"expiresAt": "2026-12-31T23:59:59Z"
|
||||
},
|
||||
"aml": {
|
||||
"passed": true,
|
||||
"provider": "Chainalysis",
|
||||
"lastCheck": "2025-01-15T09:00:00Z",
|
||||
"riskLevel": "LOW"
|
||||
}
|
||||
},
|
||||
"proof": {
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2025-01-15T10:00:00Z",
|
||||
"verificationMethod": "did:web:example.com:issuer#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5Vz5V"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Entra Verified ID Integration
|
||||
|
||||
```typescript
|
||||
// Request verified credential from Entra
|
||||
const requestCredential = async (userId: string) => {
|
||||
const response = await fetch('https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/request', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
credentialType: 'ComplianceCredential',
|
||||
claims: {
|
||||
lei: user.lei,
|
||||
kycLevel: user.kyc.level
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return response.json();
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Audit Trail Requirements
|
||||
|
||||
### Audit Log Structure
|
||||
|
||||
```typescript
|
||||
interface AuditLog {
|
||||
planId: string;
|
||||
timestamp: string;
|
||||
event: 'PLAN_CREATED' | 'COMPLIANCE_CHECKED' | 'EXECUTION_STARTED' | 'EXECUTION_COMPLETED' | 'EXECUTION_FAILED';
|
||||
userId: string;
|
||||
compliance: {
|
||||
lei: string;
|
||||
did: string;
|
||||
kyc: KYCStatus;
|
||||
aml: AMLStatus;
|
||||
};
|
||||
metadata: {
|
||||
steps: PlanStep[];
|
||||
dltTxHash?: string;
|
||||
isoMessageId?: string;
|
||||
notaryProof?: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Audit Trail Storage
|
||||
|
||||
1. **On-Chain (NotaryRegistry)**: Immutable proof hashes
|
||||
2. **Off-Chain (Database)**: Full audit logs with compliance data
|
||||
3. **ISO Messages**: Compliance data embedded in messages
|
||||
|
||||
### Compliance Audit Report
|
||||
|
||||
```typescript
|
||||
interface ComplianceAuditReport {
|
||||
planId: string;
|
||||
executionDate: string;
|
||||
user: {
|
||||
userId: string;
|
||||
lei: string;
|
||||
did: string;
|
||||
};
|
||||
compliance: {
|
||||
kyc: {
|
||||
level: number;
|
||||
provider: string;
|
||||
verified: boolean;
|
||||
expiresAt: string;
|
||||
};
|
||||
aml: {
|
||||
passed: boolean;
|
||||
provider: string;
|
||||
lastCheck: string;
|
||||
riskLevel: string;
|
||||
};
|
||||
};
|
||||
workflow: {
|
||||
steps: PlanStep[];
|
||||
totalAmount: number;
|
||||
currency: string;
|
||||
};
|
||||
receipts: {
|
||||
dltTxHash: string;
|
||||
isoMessageId: string;
|
||||
notaryProof: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Compliance Workflow Integration
|
||||
|
||||
### Step 1: User Registration
|
||||
|
||||
```typescript
|
||||
// User registers LEI and DID
|
||||
await complianceEngine.registerLEI(userId, lei);
|
||||
await complianceEngine.registerDID(userId, did);
|
||||
```
|
||||
|
||||
### Step 2: KYC Verification
|
||||
|
||||
```typescript
|
||||
// Run KYC verification (Level 2+ for fiat workflows)
|
||||
const kycResult = await complianceEngine.verifyKYC(userId, 2);
|
||||
if (!kycResult.verified) {
|
||||
throw new Error('KYC verification failed');
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: AML Screening
|
||||
|
||||
```typescript
|
||||
// Run AML screening for payments > threshold
|
||||
const amlResult = await complianceEngine.screenAML(userId, amount, 'EUR');
|
||||
if (!amlResult.passed) {
|
||||
throw new Error('AML screening failed');
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Workflow Compliance Check
|
||||
|
||||
```typescript
|
||||
// Validate compliance before execution
|
||||
const complianceCheck = await complianceEngine.validateWorkflowCompliance(workflow);
|
||||
if (!complianceCheck.valid) {
|
||||
throw new Error(`Missing compliance: ${complianceCheck.missing.join(', ')}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: ISO Message Generation
|
||||
|
||||
```typescript
|
||||
// Generate ISO message with compliance data
|
||||
const isoMessage = generateISO20022Message(plan, {
|
||||
lei: complianceStatus.lei,
|
||||
did: complianceStatus.did,
|
||||
kyc: complianceStatus.kyc,
|
||||
aml: complianceStatus.aml,
|
||||
signature: planSignature
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Error Handling
|
||||
|
||||
### Compliance Validation Failures
|
||||
|
||||
```typescript
|
||||
// Compliance check fails
|
||||
if (!complianceCheck.valid) {
|
||||
return {
|
||||
error: 'COMPLIANCE_REQUIRED',
|
||||
message: `Missing compliance attributes: ${complianceCheck.missing.join(', ')}`,
|
||||
missing: complianceCheck.missing,
|
||||
required: complianceCheck.required
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### KYC Expiration Warning
|
||||
|
||||
```typescript
|
||||
// Check if KYC is expiring soon
|
||||
if (complianceStatus.kyc.expiresAt) {
|
||||
const expiresAt = new Date(complianceStatus.kyc.expiresAt);
|
||||
const daysUntilExpiry = (expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
|
||||
|
||||
if (daysUntilExpiry < 30) {
|
||||
return {
|
||||
warning: 'KYC_EXPIRING_SOON',
|
||||
message: `KYC expires in ${daysUntilExpiry} days`,
|
||||
expiresAt: complianceStatus.kyc.expiresAt
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Testing Requirements
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```typescript
|
||||
describe('ComplianceEngine', () => {
|
||||
it('should validate LEI format', () => {
|
||||
expect(validateLEI('5493000IBP32UQZ0KL24')).toBe(true);
|
||||
expect(validateLEI('invalid')).toBe(false);
|
||||
});
|
||||
|
||||
it('should check workflow compliance', async () => {
|
||||
const result = await complianceEngine.validateWorkflowCompliance(workflow);
|
||||
expect(result.valid).toBe(true);
|
||||
expect(result.missing).toEqual([]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
```typescript
|
||||
describe('ISO Message Generation', () => {
|
||||
it('should inject compliance data into pacs.008', () => {
|
||||
const message = generateISO20022Message(plan, complianceData);
|
||||
expect(message).toContain('<LEI>5493000IBP32UQZ0KL24</LEI>');
|
||||
expect(message).toContain('<DID>did:web:example.com:user:123</DID>');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: 2025-01-15
|
||||
**Author**: Compliance Team
|
||||
|
||||
Reference in New Issue
Block a user