{ // Example configuration for the Archivist pipeline. // Keys in English; extracted values and rendered file names are in // French, as they appear in the source documents. // ========================================================================== // fields: declaration of every field handled by the rules. // A missing mandatory field at the end of the pipeline marks the document // invalid and routes it to pending/ for human review. // "template" is a regular field: rules select the naming template with it. // ========================================================================== "fields": [ { "name": "emittingCompany", "type": "text", "mandatory": true }, { "name": "documentType", "type": "enum", "mandatory": true }, { "name": "date", "type": "string", "mandatory": true }, { "name": "template", "type": "text", "mandatory": false }, { "name": "bankAccount", "type": "enum", "mandatory": false }, { "name": "address", "type": "text", "mandatory": false }, { "name": "reference", "type": "text", "mandatory": false } ], // ========================================================================== // rules: an ordered tree evaluated against the first-page text // (firstPageText) and the fields already set or deleted by earlier rules. // // Each rule contains four keys: // when (required): expr-lang expression; the rest of the rule runs only // if it evaluates to true. String literals inside // expressions are written as raw strings with backticks. // set : list of assignments // { "field": "x", "value": } constant // { "field": "x", "eval": "" } evaluated in the // same context // delete: list of field names to unset // rules : child rules, evaluated in order only if the parent "when" // matched; nesting is recursive // // Built-in helpers: firstMatch(regex) returns the first match of the regex // in the first-page text (first capture group when present). // parseDate(value, layout) parses a string into a native date (Go layout, // e.g. `02/01/2006` for 15/01/2026); the format is carried by the rule so // it can differ per document type. // ========================================================================== "rules": [ // --- Generic extraction, runs for every document ------------------------- // Emission date, e.g. "Paris, le 15/01/2026" -> "15/01/2026" { "when": "true", "set": [ { "field": "date", "eval": "parseDate(firstMatch(`[0-9]{2}/[0-9]{2}/[0-9]{4}`), `02/01/2006`)" } ] }, // --- Bank statements (relevés de compte) ---------------------------------- { "when": "firstPageText contains `Relevé de compte`", "set": [ { "field": "documentType", "value": "Relevé de compte" }, { "field": "template", "value": "bank_statement" } ], "rules": [ // Issuing bank { "when": "firstPageText contains `BRED`", "set": [ { "field": "emittingCompany", "value": "BRED" } ] }, { "when": "firstPageText contains `Fortunéo`", "set": [ { "field": "emittingCompany", "value": "Fortunéo" } ] }, { "when": "firstPageText contains `Crédit Mutuel`", "set": [ { "field": "emittingCompany", "value": "Crédit Mutuel" } ] }, // Personal accounts, matched on the account number printed on page 1 { "when": "firstPageText contains `12345678901`", "set": [ { "field": "bankAccount", "value": "Compte Thomas" } ] }, { "when": "firstPageText contains `98765432109`", "set": [ { "field": "bankAccount", "value": "Compte joint" } ] } ] }, // --- Taxe d'habitation, one child rule per address ------------------------ { "when": "firstPageText contains `Taxe d'habitation`", "set": [ { "field": "documentType", "value": "Taxe d'habitation" }, { "field": "emittingCompany", "value": "DGFiP" }, { "field": "template", "value": "tax_notice_housing" } ], "rules": [ { "when": "firstPageText contains `12 rue des Lilas`", "set": [ { "field": "address", "value": "12 rue des Lilas, Paris" } ] }, { "when": "firstPageText contains `34 avenue Jean Jaurès`", "set": [ { "field": "address", "value": "34 avenue Jean Jaurès, Bordeaux" } ] } ] }, // --- Avis d'impôt sur le revenu -------------------------------------------- { "when": "firstPageText contains `Impôt sur le revenu` && firstPageText contains `avis d'imposition`", "set": [ { "field": "documentType", "value": "Avis d'impôt sur le revenu" }, { "field": "emittingCompany", "value": "DGFiP" }, { "field": "template", "value": "tax_notice_income" } ] }, // --- Generic invoices (e-commerce and others) ----------------------------- { "when": "firstPageText contains `Facture` && firstPageText contains `TVA`", "set": [ { "field": "documentType", "value": "Facture" }, { "field": "template", "value": "invoice" }, // Invoice number, e.g. "Facture n° F-2026-0123" -> "F-2026-0123" { "field": "reference", "eval": "firstMatch(`[Ff]acture n° ?([A-Za-z0-9-]+)`)" } ], // Fields that do not apply to invoices, in case an earlier rule // set them "delete": [ "bankAccount", "address" ], "rules": [ { "when": "firstPageText contains `Amazon`", "set": [ { "field": "emittingCompany", "value": "Amazon" } ] }, { "when": "firstPageText contains `LDLC`", "set": [ { "field": "emittingCompany", "value": "LDLC" } ] }, { "when": "firstPageText contains `Cdiscount`", "set": [ { "field": "emittingCompany", "value": "Cdiscount" } ] } ] } ], // ========================================================================== // templates: named naming templates, selected by the "template" field. // The rendered template is the full object path under files/. // {date} is rendered as yyyy-mm-dd when set (normalized; "/" is not usable // in a S3 key). A field that no rule has set renders as an empty string. // If no rule sets "template", the "default" template is used. // ========================================================================== "templates": { "bank_statement": "{emittingCompany}/{date}_{documentType}_{bankAccount}.pdf", "tax_notice_housing": "Impots/{date}_{documentType}_{address}.pdf", "tax_notice_income": "Impots/{date}_{documentType}.pdf", "invoice": "Factures/{date}_{emittingCompany}_{reference}.pdf", "default": "Divers/{documentType}.pdf" } }