TCR Pipeline — FATCA Chapter 4 + CRS OCDE
Modules :
tcr-svc(orchestrateur Temporal),indicia-collector,classifier-engine,balance-aggregator,xml-generator,submit-adapter.ADRs : ADR-001 (Temporal), ADR-005 (MinIO WORM), ADR-007 (capture indicia), ADR-025 (DSL réutilisé), ADR-026 (CPS), ADR-034 (architecture TCR).
POCs : poc-fatca-generator (XML FATCA v2.0 DGI TN/IRS), poc-crs-generator (XML CRS v2.0 OCDE).
Standards : IRS Pub 5124 (FATCA XML v2.0), OECD CRS XML User Guide v2.0, IGA Tunisie-USA modèle 1 (2014), Loi 2016-71 (Tunisie CRS).
Ce document fixe la spec d’ingénierie complète de la pipeline TCR (Tax Compliance & Reporting). Un développeur backend doit pouvoir, sans question résiduelle :
- Comprendre le flow annuel de déclaration FATCA + CRS d’un FFI tenant.
- Implémenter chaque sous-module avec ses contrats, son schema d’erreurs, ses idempotency keys.
- Câbler les règles de classifier déterministes (DSL Kotlin, versionnées YAML).
- Câbler les adapters core banking pour récupérer les soldes en fin d’année + paiements.
- Générer, signer et soumettre les XML conformes — y compris corrections et nil reports.
- Respecter les obligations conformité (DGI TN, IRS Pub 5124, OECD CRS, retention 10 ans WORM).
1. Vue d’ensemble
Section intitulée « 1. Vue d’ensemble »Flow annuel nominal (FFI tunisien, exercice civil) :
| Date | Étape |
|---|---|
| 2026-01-15 | Scheduler arme le workflow TcrAnnualReportingWorkflow(year=2025) pour chaque tenant. |
| 2026-01-15→01-31 | indicia-collector consolide tous les indicia capturés via Form Designer + CPS sur l’exercice. |
| 2026-02-01→02-15 | classifier-engine classe chaque compte/entité (US person, Passive NFE, etc.) et identifie les controlling persons. |
| 2026-02-15→02-28 | balance-aggregator collecte soldes 31/12/2025 + paiements 2025 par compte. |
| 2026-03-01→03-10 | xml-generator produit FATCA + CRS, validation XSD, business rules. |
| 2026-03-10→03-25 | Compliance officer + DAF signent dual-control XAdES. |
| 2026-03-25 | submit-adapter soumet à la DGI TN (CRS due 31/05, FATCA due 30/09). |
| 2026-04→09 | Suivi AR, corrections OECD2 si erreurs, ré-soumission si nécessaire. |
2. indicia-collector — capture des indicia
Section intitulée « 2. indicia-collector — capture des indicia »2.1 Sources d’indicia
Section intitulée « 2.1 Sources d’indicia »| Source | Nature | Persistance |
|---|---|---|
Form Designer (ADR-007) field type INDICIA_FATCA | déclaratif client à l’onboarding et reviews périodiques | persiste en submission.values chiffré PII |
| OCR documents (passeport, CNI) | lieu de naissance non-déclaratif | persiste après extraction |
| Adresse de résidence (Form + CPS) | indicia US address ou résidence fiscale étrangère | CPS variable client.country |
| Téléphone (Form) | indicia US phone (+1) | CPS variable client.phone |
| Pouvoir et représentation (Form) | US POA / signataire US | CPS variable client.usPOA |
| Standing instructions (core banking) | virements récurrents vers US | adapter core banking |
| Joint account (core banking) | titulaire conjoint US | adapter core banking |
2.2 Liste figée des indicia FATCA (selon IGA TN 2014, Annexe I)
Section intitulée « 2.2 Liste figée des indicia FATCA (selon IGA TN 2014, Annexe I) »| Indicia | CPS path | Effet présomption |
|---|---|---|
| US citizenship | client.usCitizen | US Person |
| US birthplace | client.usBirth | US Person (sauf pièce justifiant de la perte de nationalité) |
| US current address | client.usAddress | US Person |
| US mailing address (incl. PO Box, “in care of”) | client.usMailingAddress | US Person |
| US phone (single phone listed and is US) | client.usPhone | US Person |
| Standing instructions to US | client.usStandingInstructions | US Person |
| US Power of Attorney / signatory | client.usPOA | US Person |
| US “in-care-of” or hold-mail address as sole address | client.usHoldMail | US Person |
2.3 Liste figée des indicia CRS (OECD CRS Implementation Handbook)
Section intitulée « 2.3 Liste figée des indicia CRS (OECD CRS Implementation Handbook) »| Indicia | CPS path | Effet |
|---|---|---|
| Tax residence country (déclaration client) | client.taxResidences[] | Reportable Person si résidence ≠ pays de l’IF déclarante |
| Current address in foreign jurisdiction | client.foreignCurrentAddress | indice résidence fiscale |
| Multiple foreign phone numbers | client.foreignPhones[] | indice résidence multiple |
| Foreign POA | client.foreignPOA | indice résidence |
| Hold-mail / in-care-of in foreign jurisdiction | client.foreignHoldMail | indice résidence |
POST /v1/tcr/indicia/collect{ "tenant_id": "TN-BANQUEX", "reporting_period": "2025-01-01/2025-12-31", "scope": "all" }→ { "collect_id": "...", "account_count": 482000, "indicia_snapshot_ref": "minio://..." }3. classifier-engine — règles déterministes versionnées
Section intitulée « 3. classifier-engine — règles déterministes versionnées »3.1 Catégories à attribuer
Section intitulée « 3.1 Catégories à attribuer »enum class FatcaStatus { SPECIFIED_US_PERSON, NON_US_PERSON, REPORTING_FFI, NON_REPORTING_FFI, ACTIVE_NFE, PASSIVE_NFE, EXEMPT_BENEFICIAL_OWNER}
enum class CrsStatus { REPORTABLE_PERSON, // résidence fiscale dans une juridiction CRS partenaire NON_REPORTABLE, REPORTING_FI, NON_REPORTING_FI, ACTIVE_NFE, PASSIVE_NFE}3.2 DSL Kotlin (réutilise grammaire Risk Engine, ADR-025)
Section intitulée « 3.2 DSL Kotlin (réutilise grammaire Risk Engine, ADR-025) »val classifierFatca = classifierPolicy { id = "fatca-tn-banquex-v2.0" version = "2.0.1" description = "Classification FATCA, IGA TN modèle 1, IRS Pub 5124"
rule("specified_us_person_individual") { whenever { (subject("kind") eq "INDIVIDUAL") and ((field("client.usCitizen") eq true) or (field("client.usBirth") eq true) or (field("client.usAddress") eq true) or (field("client.usMailingAddress") eq true) or (field("client.usPhone") eq true) or (field("client.usStandingInstructions") eq true) or (field("client.usPOA") eq true)) } then = assignStatus(FatcaStatus.SPECIFIED_US_PERSON) }
rule("active_nfe_business") { whenever { (subject("kind") eq "ENTITY") and (field("entity.passiveIncomeRatio") lt 0.5) and (field("entity.passiveAssetRatio") lt 0.5) } then = assignStatus(FatcaStatus.ACTIVE_NFE) }
rule("passive_nfe_default") { whenever { (subject("kind") eq "ENTITY") and not(matched("active_nfe_business")) and not(matched("reporting_ffi")) } then = assignStatus(FatcaStatus.PASSIVE_NFE) }
// ... 12 règles au total couvrant FATCA Annexe I IGA TN}Versionnage : chaque policy a un id + version SemVer + hash SHA-256 + signature Ed25519 dual-control compliance + DGI. Toute évolution exige une nouvelle version (audit).
3.3 Détermination des controlling persons (Passive NFE)
Section intitulée « 3.3 Détermination des controlling persons (Passive NFE) »Pour toute entité classifiée PASSIVE_NFE, identifier les personnes physiques exerçant un contrôle :
| Type de contrôle | Définition CRS | Source |
|---|---|---|
| Détention capital ≥ 25 % | direct ou indirect | RNE (POC poc-rne-connector) + déclaration UBO |
| Contrôle par autres moyens | accord, contrat, vote | déclaration client |
| Senior managing official | si aucun contrôle ≥ 25 % identifié | KBIS / déclaration |
L’engine produit pour chaque Passive NFE la liste des ControllingPerson avec leur statut FATCA/CRS individuel.
POST /v1/tcr/classify{ "tenant_id": "...", "snapshot_ref": "minio://...", "policy_id": "fatca-tn-banquex-v2.0", "reporting_period": "2025-..." }→ { "classification_ref": "minio://...", "classified_accounts": 482000, "specified_us_persons": 87, "passive_nfes": 1240, "audit": {...} }4. balance-aggregator — soldes et paiements
Section intitulée « 4. balance-aggregator — soldes et paiements »4.1 Données à collecter par compte
Section intitulée « 4.1 Données à collecter par compte »| Champ XML | Source core banking |
|---|---|
AccountBalance (au 31/12) | enquiry STMT.ENT.BOOK ou équivalent (cf POC Temenos T24) |
Payment[Interest] (intérêts versés sur l’exercice) | classification écritures par type |
Payment[Dividends] | classification écritures (titres) |
Payment[GrossProceeds/Redemptions] | écritures de cession titres |
Payment[Other] | reste applicable |
4.2 Adapters
Section intitulée « 4.2 Adapters »Format pivot CanonicalAccountSnapshot identique pour tous les core banking. Adapters disponibles ou à faire :
| Core banking | Adapter | Statut |
|---|---|---|
| Temenos T24 / Transact | temenos-connector | POC livré |
| Sopra Banking Platform | sopra-connector | À faire |
| Oracle FlexCube / FCC | fcc-connector | À faire |
| Path Solutions iMAL | imal-connector | À faire |
| Custom on-prem (CSV / SQL view) | csv-connector | À faire fallback |
4.3 Multi-devise
Section intitulée « 4.3 Multi-devise »Soldes et paiements stockés dans leur devise d’origine (CurrCode ISO 4217). FATCA et CRS acceptent multi-devise sans conversion. La devise est déclarée par compte.
5. xml-generator — schémas FATCA et CRS
Section intitulée « 5. xml-generator — schémas FATCA et CRS »5.1 FATCA XML v2.0 — éléments obligatoires
Section intitulée « 5.1 FATCA XML v2.0 — éléments obligatoires »<FATCA_OECD version="2.0"> <MessageSpec> <SendingCompanyIN>...</SendingCompanyIN> <TransmittingCountry>TN</TransmittingCountry> <ReceivingCountry>US</ReceivingCountry> <MessageType>FATCA</MessageType> <Warning>...</Warning> <Contact>...</Contact> <MessageRefId>{TIN}-{year}-{seq}</MessageRefId> <ReportingPeriod>2025-12-31</ReportingPeriod> <Timestamp>2026-03-25T10:00:00</Timestamp> </MessageSpec> <FATCA> <ReportingFI> <Name>...</Name> <Address>...</Address> <DocSpec>...</DocSpec> <FilerCategory>FATCA601</FilerCategory> </ReportingFI> <ReportingGroup> <Sponsor>...</Sponsor> <!-- optionnel --> <NilReport>...</NilReport> <!-- mutuellement exclusif AccountReport --> <AccountReport> <DocSpec>...</DocSpec> <AccountNumber>...</AccountNumber> <AccountHolder> <Individual>...</Individual> OR <Organisation>...</Organisation> </AccountHolder> <SubstantialOwner>...</SubstantialOwner> <!-- pour Passive NFE --> <AccountBalance currCode="TND">12345.67</AccountBalance> <Payment> <Type>FATCA501</Type> <!-- Interest --> <PaymentAmnt currCode="TND">123.45</PaymentAmnt> </Payment> </AccountReport> </ReportingGroup> </FATCA></FATCA_OECD>POC poc-fatca-generator couvre déjà la génération conforme.
5.2 CRS XML v2.0 — éléments obligatoires
Section intitulée « 5.2 CRS XML v2.0 — éléments obligatoires »<CRS_OECD version="2.0"> <MessageSpec> <SendingCompanyIN>...</SendingCompanyIN> <TransmittingCountry>TN</TransmittingCountry> <ReceivingCountry>FR</ReceivingCountry> <MessageType>CRS</MessageType> <MessageTypeIndic>CRS701</MessageTypeIndic> <!-- New | Correction | Void --> <MessageRefId>...</MessageRefId> <ReportingPeriod>2025-12-31</ReportingPeriod> <Timestamp>2026-03-25T10:00:00</Timestamp> </MessageSpec> <CrsBody> <ReportingFI> <ResCountryCode>TN</ResCountryCode> <Name>...</Name> <Address>...</Address> <DocSpec>...</DocSpec> </ReportingFI> <ReportingGroup> <AccountReport> <DocSpec>...</DocSpec> <AccountNumber>...</AccountNumber> <AccountHolder> <Individual> <ResCountryCode>FR</ResCountryCode> <TIN issuedBy="FR">...</TIN> <Name> <FirstName>...</FirstName> <LastName>...</LastName> </Name> <Address>...</Address> <BirthInfo> <BirthDate>1980-05-15</BirthDate> </BirthInfo> </Individual> OR <Organisation> <ResCountryCode>FR</ResCountryCode> <IN issuedBy="FR">...</IN> <Name>...</Name> <Address>...</Address> <AcctHolderType>CRS101</AcctHolderType> <!-- Passive NFE controlled by Reportable Person --> </Organisation> </AccountHolder> <ControllingPerson>...</ControllingPerson> <!-- pour Passive NFE --> <AccountBalance currCode="TND">12345.67</AccountBalance> <Payment>...</Payment> </AccountReport> </ReportingGroup> </CrsBody></CRS_OECD>POC poc-crs-generator (cf /engineering/poc-crs-generator/) couvre les cas standards et nil report.
5.3 Différences clés FATCA vs CRS
Section intitulée « 5.3 Différences clés FATCA vs CRS »| Aspect | FATCA | CRS |
|---|---|---|
ReceivingCountry | toujours US | pays partenaire variable (résidence du Reportable Person) |
AcctHolderType | non | obligatoire pour Passive NFE (CRS101/CRS102/CRS103) |
MessageTypeIndic | non | obligatoire (CRS701 New, CRS702 Correction, CRS703 Void) |
| Bilatéral vs multilatéral | bilatéral US | multilatéral (1 fichier par pays receveur) |
| TIN obligatoire | oui pour US | recommandé fortement, manque toléré dans certains cas |
| Fréquence | annuelle | annuelle |
6. Validation et signature
Section intitulée « 6. Validation et signature »6.1 Validation à 2 niveaux
Section intitulée « 6.1 Validation à 2 niveaux »| Niveau | Vérifications |
|---|---|
| XSD | conformité schéma — toute violation est un rejet immédiat |
| Business rules | TIN valide, dates cohérentes (ReportingPeriod ≤ Timestamp ≤ now), totals balance ≥ 0 ou flag négatif autorisé, présence ControllingPerson sur Passive NFE, MessageRefId unique |
6.2 Signature XAdES-BES
Section intitulée « 6.2 Signature XAdES-BES »Exigence DGI Tunisie : signature électronique XAdES (Tunisie utilise XAdES-BES sur le fichier final). Clé tenant via Vault + KMS.
6.3 Dual-control
Section intitulée « 6.3 Dual-control »Le workflow Temporal exige 2 signatures humaines (Compliance Officer + DAF) avant submit-adapter. Pas de soumission auto.
7. submit-adapter — soumission
Section intitulée « 7. submit-adapter — soumission »7.1 DGI Tunisie (FATCA via IGA modèle 1, et CRS local)
Section intitulée « 7.1 DGI Tunisie (FATCA via IGA modèle 1, et CRS local) »Portail HTTPS DGI : POST authentifié + fichier signé XAdES. Adapter HTTP custom (pas d’API standardisée publique avant 2024 ; à confirmer auprès de DGI fin 2026).
7.2 IRS IDES (alternative pour FFI directement reporting type IGA 2)
Section intitulée « 7.2 IRS IDES (alternative pour FFI directement reporting type IGA 2) »SFTP avec encryption M3M (chiffrement du fichier avant envoi avec certificate IDES public). Adapter SFTP+OpenSSL.
7.3 Acknowledgement Receipt
Section intitulée « 7.3 Acknowledgement Receipt »Après soumission, polling sur le portail (DGI) ou récupération SFTP (IRS) du fichier AR :
Accepted: OK, archivé.AcceptedWithErrors: warnings non bloquants. À examiner.Rejected: analyser, corriger, soumettreOECD2(CRS) ou amendement (FATCA).
7.4 Corrections / Annulations
Section intitulée « 7.4 Corrections / Annulations »| Type | FATCA | CRS |
|---|---|---|
| Correction d’un AccountReport | nouveau MessageRefId + DocTypeIndic OECD2 + référence DocRefId d’origine | idem, MessageTypeIndic = CRS702 |
| Annulation totale | DocTypeIndic OECD3 Void | MessageTypeIndic = CRS703 |
| Resubmit (rejet original) | nouveau MessageRefId + reprend les comptes corrigés | idem |
8. Storage et audit
Section intitulée « 8. Storage et audit »| Artefact | Storage | Retention | Hash |
|---|---|---|---|
| Snapshot indicia (par exercice) | MinIO tcr/{tenant}/{year}/indicia.json.enc | 10 ans WORM | SHA-256 dans audit ledger |
| Classification result | MinIO tcr/{tenant}/{year}/classification.json.enc | 10 ans WORM | idem |
| Balance snapshot | MinIO tcr/{tenant}/{year}/balances.json.enc | 10 ans WORM | idem |
| XML FATCA généré + signé | MinIO tcr/{tenant}/{year}/fatca.xml.signed | 10 ans WORM | hash + sig |
| XML CRS par pays | MinIO tcr/{tenant}/{year}/crs/{country}.xml.signed | 10 ans WORM | hash + sig |
| Acknowledgement Receipts | MinIO tcr/{tenant}/{year}/ar/{filename} | 10 ans WORM | idem |
| Audit ledger | PostgreSQL append-only | 10 ans WORM | chaque ligne hashée chained |
9. API REST (résumé)
Section intitulée « 9. API REST (résumé) »| Méthode | Endpoint | Description |
|---|---|---|
POST | /v1/tcr/workflows/run | déclenche manuellement un workflow annuel pour un tenant et une période |
GET | /v1/tcr/workflows/:id | suit l’avancement |
GET | /v1/tcr/workflows/:id/audit | trace complète |
POST | /v1/tcr/sign | signature dual-control d’un XML prêt |
POST | /v1/tcr/submit | soumet à la DGI ou IRS |
POST | /v1/tcr/correction | démarre un workflow de correction OECD2 |
OpenAPI complet : voir /api/openapi/ section TCR.
10. Performance et capacité
Section intitulée « 10. Performance et capacité »| Metric | MVP | V2 |
|---|---|---|
| Génération XML 10 K comptes | ≤ 30 s | ≤ 10 s |
| Génération XML 1 M comptes | ≤ 8 min | ≤ 3 min |
| Soumission DGI (round-trip portal) p95 | ≤ 60 s | ≤ 30 s |
| AR polling fréquence | toutes les 30 min | webhook DGI si disponible |
| Validation XSD pass rate | 100 % | 100 % |
| AR rejected rate | ≤ 5 % | ≤ 1 % |
11. Sécurité et privacy
Section intitulée « 11. Sécurité et privacy »- Données : TIN, soldes, paiements = SPI. Chiffrement enveloppe AES-256-GCM, KEK per-tenant. Pas de log clair.
- Accès : seul
tcr-svclit les balances ; les rôles compliance et DAF accèdent via UI signée. - Audit : chaque accès tracé avec
actor,action,timestamp,dataRef, signature. - Signatures : Ed25519 sur le hash du XML après XAdES, double signature obligatoire.
- Transmission : DGI portail HTTPS + cert pinning ; IRS SFTP + encryption M3M.
- DPIA : traitement légal
obligation légale(RGPD art. 6.1.c). Pas de consentement requis. Cf DPIA.
12. Conformité
Section intitulée « 12. Conformité »| Référence | Exigence | Couverture |
|---|---|---|
| IGA TN-USA modèle 1 (2014) | classification + déclaration via DGI | classifier + xml-gen + submit DGI ✓ |
| IRS Pub 5124 v2.0 | XML schema FATCA | xml-generator FATCA ✓ |
| OECD CRS XML User Guide v2.0 | XML schema CRS | xml-generator CRS ✓ |
| Loi 2016-71 (Tunisie CRS) | échange automatique d’informations | classifier + soumission DGI ✓ |
| DGI TN procédures | dépôt portail signé XAdES | submit-adapter DGI ✓ |
| §6041 / §1471 IRC | accuracy reporting | dual-control + retention 10 ans ✓ |
| RGPD art. 6.1.c | obligation légale | DPIA ✓ |
13. Plan de migration MVP → V2
Section intitulée « 13. Plan de migration MVP → V2 »| Item | MVP | V2 |
|---|---|---|
| Adapters core banking | Temenos T24 | + Sopra + FCC + iMAL |
| Submit DGI | portail manuel + automatisé HTTP | API officielle si publiée |
| Submit IRS IDES | si tenant IGA 2 | full automation |
| OECD partenaires CRS supportés | TOP 30 (couvre 95 % volumes TN) | tous |
| Sponsor model | non | oui |
| Reporting period non-civil | non | oui |
| Alimentation auto FATCA W-8/W-9 forms | non | oui |
14. Checklist go-live MVP
Section intitulée « 14. Checklist go-live MVP »- DSL classifier compilé sur 12 règles FATCA + 8 règles CRS, signé policy v2.0.0
-
indicia-collectorconsume Form Designer events + CPS sans drift -
balance-aggregatorTemenos T24 valide sur 100 K comptes pilote -
xml-generatorFATCA + CRS validés XSD sur 50 cas tests - Signature XAdES-BES opérationnelle avec KMS Vault
- Dual-control workflow approuvé compliance + DAF
- Submit-adapter DGI testé sur sandbox DGI 2026
- AR polling + corrections OECD2 fonctionnels
- Storage WORM 10 ans configuré sur MinIO
- Audit ledger PostgreSQL append-only signé
- DPIA mise à jour
- Runbook on-call : flow incident soumission (portail down, AR rejected)
15. Références
Section intitulée « 15. Références »- ADR : ADR-034
- POCs : poc-fatca-generator, poc-crs-generator
- Standards : IRS Pub 5124, OECD CRS, IRS IDES, DGI Tunisie
- ADRs liés : ADR-001, ADR-005, ADR-007, ADR-025, ADR-026
Document de spec pipeline TCR — version 1.0 (2026-04-29). Mises à jour bloquantes nécessitent un ADR.