Document Purpose: Explain the complexity of creating XBRL documents collaboratively over time, the work-in-progress challenges, and architectural solutions including GLOMIDCO's proven BPM/CMIS/ESB approach
Last Updated: January 2026
Target Audience: Enterprise architects, XBRL implementers, workflow designers, system integrators
The Reality:
XBRL documents like annual reports ("Jaarrekening") and audit reports ("Controle verklaring") are not created in one sitting by one person. They are:
The Challenge:
Traditional Document (Word, PDF):
├─ Easy to edit collaboratively
├─ Track changes built-in
├─ Comments and annotations
├─ View at any stage
└─ Standard collaboration tools
XBRL Document:
├─ Complex structured data
├─ Must remain valid (or validatable)
├─ Multiple interdependent parts
├─ Requires specialized tools
├─ No standard collaboration approach
└─ Validation expensive/complex
Example Workflow - Dutch Annual Report:
January-June: Create Jaarrekening (Annual Report)
├─ Month 1: Accountant inputs financial data
├─ Month 2: Tax specialist adds tax positions
├─ Month 3: Asset valuator updates valuations
├─ Month 4: Controller reviews and adjusts
├─ Month 5: Auditor reviews and requests changes
├─ Month 6: Final approval and signing
│
└─ At each stage:
├─ Document is INCOMPLETE
├─ Multiple people need to VIEW current state
├─ Specific people need to EDIT their parts
├─ Validation needed before next stage
└─ Signatures required at milestones
GLOMIDCO Solution Architecture (Proven 2014):
┌─────────────────────────────────────────────────┐
│ BPM Layer (Workflow Management) │
│ ├─ Process definitions │
│ ├─ Task assignments │
│ ├─ Approval flows │
│ └─ References to CMIS documents │
└──────────────────┬──────────────────────────────┘
│
┌──────────────────▼──────────────────────────────┐
│ CMIS Layer (Extended for XBRL) │
│ ├─ XBRL document storage │
│ ├─ Multiple viewpoints │
│ ├─ Multilayered documents │
│ ├─ Version control │
│ └─ Access control per section │
└──────────────────┬──────────────────────────────┘
│
┌──────────────────▼──────────────────────────────┐
│ ESB Layer (Service Integration) │
│ ├─ XBRL validation service │
│ ├─ Viewpoint generation service │
│ ├─ XAdES signing service │
│ ├─ Schema generation service │
│ └─ Transformation services │
└──────────────────┬──────────────────────────────┘
│
┌──────────────────▼──────────────────────────────┐
│ GLOMIDCO XBRL Processor (Core Engine) │
│ ├─ XBRL parsing and generation │
│ ├─ Validation engine │
│ ├─ Viewpoint rendering │
│ └─ Three-phase architecture │
└─────────────────────────────────────────────────┘
Key Innovations:
Result:
Traditional Document Creation:
Word Document: Annual Report
├─ Author writes draft (Week 1)
├─ Reviewer adds comments (Week 2)
├─ Author revises (Week 3)
├─ Final approval (Week 4)
└─ DONE
Challenges: Minimal
Tools: Word, email, SharePoint
Complexity: Low
XBRL Document Creation:
XBRL Jaarrekening (Annual Report)
├─ Accountant: Balance sheet facts (Month 1)
├─ Tax specialist: Tax disclosures (Month 2)
├─ Valuator: Asset valuations (Month 3)
├─ Controller: Consolidation adjustments (Month 4)
├─ Auditor: Audit adjustments (Month 5)
└─ Board: Final approval and signing (Month 6)
At each stage:
├─ Document is INCOMPLETE (missing required facts)
├─ Document might be INVALID (calculations don't balance)
├─ Different people need DIFFERENT VIEWS
├─ Some parts LOCKED, some EDITABLE
├─ Must track WHO changed WHAT and WHEN
└─ Legal signatures required at milestones
Challenges: SIGNIFICANT
Tools: ???
Complexity: HIGH
Problem: XBRL documents have mandatory facts that won't exist until late in the process.
Example - Dutch Annual Report (SBR Taxonomy):
<!-- Month 1: Accountant creates initial balance sheet -->
<xbrli:xbrl>
<!-- Has: Balance sheet facts -->
<nl-cd:Assets>1000000</nl-cd:Assets>
<nl-cd:Liabilities>600000</nl-cd:Liabilities>
<nl-cd:Equity>400000</nl-cd:Equity>
<!-- Missing: Tax information (added Month 2) -->
<!-- Missing: Audit opinion (added Month 5) -->
<!-- Missing: Board approval (added Month 6) -->
</xbrli:xbrl>
Questions:
Traditional approach fails:
Option 1: Don't validate until complete
└─ Risk: Errors discovered too late
Option 2: Force completeness at each stage
└─ Risk: Dummy data, artificial constraints
Option 3: Store as non-XBRL until complete
└─ Risk: No XBRL validation, conversion errors
Scenario: Creating a "Controle verklaring" (Audit Report)
Contributors:
┌─────────────────────────────────────────────┐
│ 1. Financial Accountant │
│ ├─ Responsible for: Financial statements │
│ ├─ Needs to edit: Balance sheet, P&L │
│ ├─ Needs to view: Everything │
│ └─ Timeline: Month 1-2 │
├─────────────────────────────────────────────┤
│ 2. Tax Specialist │
│ ├─ Responsible for: Tax disclosures │
│ ├─ Needs to edit: Tax section only │
│ ├─ Needs to view: Financial statements │
│ └─ Timeline: Month 2-3 │
├─────────────────────────────────────────────┤
│ 3. Asset Valuator │
│ ├─ Responsible for: Asset valuations │
│ ├─ Needs to edit: Valuation facts │
│ ├─ Needs to view: Balance sheet │
│ └─ Timeline: Month 3 │
├─────────────────────────────────────────────┤
│ 4. Controller │
│ ├─ Responsible for: Consolidation │
│ ├─ Needs to edit: All financial data │
│ ├─ Needs to view: Everything │
│ └─ Timeline: Month 4 │
├─────────────────────────────────────────────┤
│ 5. Auditor │
│ ├─ Responsible for: Audit opinion │
│ ├─ Needs to edit: Audit section │
│ ├─ Needs to view: Everything │
│ └─ Timeline: Month 5 │
├─────────────────────────────────────────────┤
│ 6. Board Member (CFO) │
│ ├─ Responsible for: Final approval │
│ ├─ Needs to edit: Nothing │
│ ├─ Needs to view: Everything │
│ └─ Timeline: Month 6 (signing) │
└─────────────────────────────────────────────┘
Challenges:
Question: When do you validate an incomplete XBRL document?
Scenarios:
Scenario A: Validate on every save
Result:
├─ Month 1: FAILS (missing tax data, audit opinion, etc.)
├─ Month 2: FAILS (missing audit opinion)
├─ Month 3: FAILS (missing audit opinion)
├─ Month 4: FAILS (missing audit opinion)
├─ Month 5: PASSES (all required facts present)
└─ Month 6: PASSES (with signatures)
Problem: Constant failure messages discourage users
Scenario B: Don't validate until month 6
Result:
├─ Month 1-5: No validation
├─ Month 6: FAILS (calculation errors from month 2!)
└─ Must go back and fix
Problem: Errors discovered too late, rework required
Scenario C: Progressive validation
Result:
├─ Month 1: Validate balance sheet (PASSES)
├─ Month 2: Validate balance sheet + tax (PASSES)
├─ Month 3: Validate balance sheet + tax + valuations (PASSES)
├─ Month 4: Validate all financial data (PASSES)
├─ Month 5: Validate with audit opinion (PASSES)
└─ Month 6: Full validation with signatures (PASSES)
Solution: Validate what's there, acknowledge what's missing
Progressive validation requires:
CMIS (Content Management Interoperability Services) is an OASIS open standard for enterprise content management interoperability.
Official Specification: OASIS CMIS Version 1.1 (2013)
Status: OASIS Standard
Website: https://www.oasis-open.org/committees/cmis/
What CMIS Provides:
CMIS Standard
├─ Domain Model (objects, types, properties)
├─ Services (repository, navigation, object, versioning, etc.)
├─ Query Language (CMIS Query Language - SQL-like)
└─ Protocol Bindings (AtomPub, SOAP, Browser JSON)
Why CMIS Matters:
CMIS Compliant Repositories:
CMIS provides THREE protocol bindings out-of-the-box:
┌─────────────────────────────────────────────────────┐
│ CMIS Standard │
├─────────────────────────────────────────────────────┤
│ │
│ 1. AtomPub Binding (REST + XML) │
│ ├─ Based on Atom Publishing Protocol │
│ ├─ RESTful HTTP operations │
│ ├─ XML representations │
│ └─ Best for: Web services, REST clients │
│ │
│ 2. Web Services (SOAP) Binding │
│ ├─ Based on SOAP 1.2 │
│ ├─ WSDL-defined operations │
│ ├─ XML messages │
│ └─ Best for: Enterprise SOA, .NET, Java EE │
│ │
│ 3. Browser (JSON) Binding │
│ ├─ RESTful HTTP operations │
│ ├─ JSON representations │
│ ├─ Optimized for browsers │
│ └─ Best for: Web apps, JavaScript clients │
│ │
└─────────────────────────────────────────────────────┘
All three bindings access the SAME underlying repository!
Example 1: AtomPub Binding
GET /cmis/atom/content?id=xbrl-doc-12345 HTTP/1.1
Host: cmis.example.com
Accept: application/atom+xml
HTTP/1.1 200 OK
Content-Type: application/atom+xml
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/">
<id>urn:uuid:xbrl-doc-12345</id>
<title>jaarrekening-2024.xbrl</title>
<updated>2024-02-20T14:30:00Z</updated>
<author>
<name>tax-specialist</name>
</author>
<content type="application/xbrl+xml"
src="http://cmis.example.com/content/xbrl-doc-12345"/>
<cmis:object>
<cmis:properties>
<cmis:propertyId propertyDefinitionId="cmis:objectId">
<cmis:value>xbrl-doc-12345</cmis:value>
</cmis:propertyId>
<cmis:propertyString propertyDefinitionId="cmis:name">
<cmis:value>jaarrekening-2024.xbrl</cmis:value>
</cmis:propertyString>
<cmis:propertyString propertyDefinitionId="xbrl:taxonomy">
<cmis:value>nl-fr-gaap-2024</cmis:value>
</cmis:propertyString>
<cmis:propertyString propertyDefinitionId="xbrl:completionStatus">
<cmis:value>60%</cmis:value>
</cmis:propertyString>
</cmis:properties>
</cmis:object>
</entry>
Example 2: SOAP Binding
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:cmis="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
<soapenv:Body>
<cmis:getObject>
<cmis:repositoryId>annual-reports</cmis:repositoryId>
<cmis:objectId>xbrl-doc-12345</cmis:objectId>
</cmis:getObject>
</soapenv:Body>
</soapenv:Envelope>
<!-- Response -->
<soapenv:Envelope>
<soapenv:Body>
<cmis:getObjectResponse>
<cmis:object>
<cmis:properties>
<cmis:propertyId propertyDefinitionId="cmis:objectId">
<cmis:value>xbrl-doc-12345</cmis:value>
</cmis:propertyId>
<cmis:propertyString propertyDefinitionId="xbrl:taxonomy">
<cmis:value>nl-fr-gaap-2024</cmis:value>
</cmis:propertyString>
</cmis:properties>
</cmis:object>
</cmis:getObjectResponse>
</soapenv:Body>
</soapenv:Envelope>
Example 3: Browser/JSON Binding
GET /cmis/browser/root/annual-reports/2024/ACME/jaarrekening-2024.xbrl?cmisselector=object HTTP/1.1
Host: cmis.example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{
"succinctProperties": {
"cmis:objectId": "xbrl-doc-12345",
"cmis:name": "jaarrekening-2024.xbrl",
"cmis:objectTypeId": "xbrl:document",
"cmis:createdBy": "accountant-user",
"cmis:creationDate": "2024-01-15T10:00:00.000Z",
"cmis:lastModifiedBy": "tax-specialist",
"cmis:lastModificationDate": "2024-02-20T14:30:00.000Z",
"xbrl:taxonomy": "nl-fr-gaap-2024",
"xbrl:entryPoint": "jaarstukken-groot",
"xbrl:reportingEntity": "12345678",
"xbrl:reportingPeriod": "2024-12-31",
"xbrl:completionStatus": "60%",
"xbrl:validationStatus": "PARTIAL_VALID",
"xbrl:currentStage": "TAX_REVIEW"
},
"propertiesExtension": {},
"allowableActions": {
"canGetProperties": true,
"canUpdateProperties": true,
"canGetContentStream": true,
"canSetContentStream": true,
"canDeleteObject": false
}
}
Choosing the Right Binding:
Use Case | Recommended Binding
───────────────────────────────────────────────────────
Java/Spring application | AtomPub or SOAP
.NET/C# application | SOAP
Web application (React/Angular) | Browser JSON
REST-first architecture | AtomPub or Browser JSON
Legacy SOA integration | SOAP
Mobile applications | Browser JSON
Node.js backend | Browser JSON
CMIS defines a sophisticated layered architecture for content:
┌─────────────────────────────────────────────────────┐
│ Layer 1: Core Object Types │
│ ├─ cmis:document (files with content) │
│ ├─ cmis:folder (containers) │
│ ├─ cmis:relationship (links between objects) │
│ ├─ cmis:policy (policies applied to objects) │
│ └─ cmis:item (custom objects without content) │
└────────────────────┬────────────────────────────────┘
│ Extends
┌────────────────────▼────────────────────────────────┐
│ Layer 2: Custom Types (Repository-Specific) │
│ ├─ invoice:document extends cmis:document │
│ ├─ contract:document extends cmis:document │
│ └─ xbrl:document extends cmis:document ← We add! │
└────────────────────┬────────────────────────────────┘
│ Instances
┌────────────────────▼────────────────────────────────┐
│ Layer 3: Objects (Actual Documents) │
│ ├─ jaarrekening-2024.xbrl (instance of xbrl:doc) │
│ ├─ jaarrekening-2023.xbrl │
│ └─ ... │
└────────────────────┬────────────────────────────────┘
│ Contains
┌────────────────────▼────────────────────────────────┐
│ Layer 4: Properties (Metadata) │
│ ├─ cmis:name = "jaarrekening-2024.xbrl" │
│ ├─ cmis:createdBy = "accountant-user" │
│ ├─ xbrl:taxonomy = "nl-fr-gaap-2024" │
│ ├─ xbrl:completionStatus = "60%" │
│ └─ ... │
└────────────────────┬────────────────────────────────┘
│ Manages
┌────────────────────▼────────────────────────────────┐
│ Layer 5: Content Streams │
│ ├─ Primary content (the XBRL-XML file) │
│ ├─ Renditions (HTML view, PDF view) │
│ └─ Thumbnails │
└────────────────────┬────────────────────────────────┘
│ Tracked by
┌────────────────────▼────────────────────────────────┐
│ Layer 6: Versions │
│ ├─ v1.0 - Initial draft by accountant │
│ ├─ v1.1 - With tax data │
│ ├─ v1.2 - With valuations │
│ └─ v2.0 - Final approved version │
└────────────────────┬────────────────────────────────┘
│ Controlled by
┌────────────────────▼────────────────────────────────┐
│ Layer 7: Access Control (ACLs) │
│ ├─ accountant: read, write financial sections │
│ ├─ tax-specialist: read all, write tax section │
│ ├─ auditor: read all, write audit section │
│ └─ CFO: read all, approve, sign │
└────────────────────┬────────────────────────────────┘
│ Supports
┌────────────────────▼────────────────────────────────┐
│ Layer 8: Relationships │
│ ├─ Links to taxonomy packages │
│ ├─ Links to supporting documents │
│ └─ Links to previous year reports │
└─────────────────────────────────────────────────────┘
CMIS defines 11 standard services:
┌────────────────────────────────────────────────────┐
│ CMIS Services │
├────────────────────────────────────────────────────┤
│ │
│ 1. Repository Services │
│ ├─ getRepositories() │
│ ├─ getRepositoryInfo() │
│ ├─ getTypeDefinition() │
│ └─ getTypeDescendants() │
│ │
│ 2. Navigation Services │
│ ├─ getChildren() │
│ ├─ getDescendants() │
│ ├─ getFolderTree() │
│ └─ getObjectParents() │
│ │
│ 3. Object Services │
│ ├─ createDocument() │
│ ├─ getObject() │
│ ├─ updateProperties() │
│ ├─ deleteObject() │
│ └─ moveObject() │
│ │
│ 4. Multi-filing Services │
│ ├─ addObjectToFolder() │
│ └─ removeObjectFromFolder() │
│ │
│ 5. Discovery Services │
│ ├─ query() -- CMIS Query Language │
│ ├─ getContentChanges() │
│ └─ search() │
│ │
│ 6. Versioning Services │
│ ├─ checkOut() │
│ ├─ checkIn() │
│ ├─ getAllVersions() │
│ └─ getLatestVersion() │
│ │
│ 7. Relationship Services │
│ ├─ getObjectRelationships() │
│ └─ createRelationship() │
│ │
│ 8. Policy Services │
│ ├─ applyPolicy() │
│ ├─ removePolicy() │
│ └─ getAppliedPolicies() │
│ │
│ 9. ACL Services │
│ ├─ getACL() │
│ └─ applyACL() │
│ │
│ 10. Rendition Services │
│ ├─ getRenditions() │
│ └─ getContentStream() (with rendition) │
│ │
│ 11. Extension Services │
│ └─ Custom operations (e.g., XBRL validation) │
│ │
└────────────────────────────────────────────────────┘
CMIS includes SQL-like query language:
-- Find all XBRL documents for 2024
SELECT cmis:objectId, cmis:name, xbrl:completionStatus
FROM xbrl:document
WHERE xbrl:reportingPeriod = '2024-12-31'
AND xbrl:validationStatus = 'VALID'
-- Find documents needing tax specialist review
SELECT cmis:objectId, cmis:name, xbrl:currentStage
FROM xbrl:document
WHERE xbrl:currentStage = 'TAX_REVIEW'
AND cmis:lastModificationDate > TIMESTAMP '2024-01-01T00:00:00.000Z'
-- Find incomplete documents
SELECT cmis:objectId, cmis:name, xbrl:completionStatus
FROM xbrl:document
WHERE xbrl:completionStatus < '100%'
ORDER BY cmis:lastModificationDate DESC
GLOMIDCO adds XBRL-specific capabilities on top of standard CMIS:
Standard CMIS GLOMIDCO Extension
─────────────────────────────────────────────────────
cmis:document → xbrl:document
+ cmis:name → + xbrl:taxonomy
+ cmis:createdBy → + xbrl:entryPoint
+ cmis:creationDate → + xbrl:reportingEntity
+ cmis:lastModifiedBy → + xbrl:reportingPeriod
+ cmis:lastModificationDate → + xbrl:completionStatus
+ cmis:objectId → + xbrl:validationStatus
+ cmis:versionLabel → + xbrl:currentStage
+ xbrl:viewpoints (JSON)
+ xbrl:sections (JSON)
+ xbrl:lockedSections (JSON)
Content Stream → XBRL Instance Content
+ getContentStream() → + parsed XBRL facts
+ contexts
+ units
Renditions → XBRL Viewpoints
+ application/pdf → + HTML viewpoint
+ image/png → + PDF viewpoint
+ Section view
+ Table view
Relationships → XBRL Links
+ parent folder → + Taxonomy package
+ Supporting docs
+ Previous period
Custom Extension Services → XBRL Operations
+ (none in standard) → + validateXBRL()
+ generateViewpoint()
+ lockSection()
+ unlockSection()
+ getRequiredFacts()
+ addSignature()
Type Definition Example:
<cmis:typeDefinition>
<cmis:id>xbrl:document</cmis:id>
<cmis:localName>xbrl:document</cmis:localName>
<cmis:displayName>XBRL Document</cmis:displayName>
<cmis:description>Extended document type for XBRL instances</cmis:description>
<cmis:baseId>cmis:document</cmis:baseId>
<cmis:parentId>cmis:document</cmis:parentId>
<cmis:creatable>true</cmis:creatable>
<cmis:queryable>true</cmis:queryable>
<cmis:controllablePolicy>false</cmis:controllablePolicy>
<cmis:controllableACL>true</cmis:controllableACL>
<cmis:fulltextIndexed>true</cmis:fulltextIndexed>
<cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
<cmis:propertyStringDefinition>
<cmis:id>xbrl:taxonomy</cmis:id>
<cmis:localName>taxonomy</cmis:localName>
<cmis:displayName>XBRL Taxonomy</cmis:displayName>
<cmis:queryName>xbrl:taxonomy</cmis:queryName>
<cmis:propertyType>string</cmis:propertyType>
<cmis:cardinality>single</cmis:cardinality>
<cmis:required>true</cmis:required>
<cmis:queryable>true</cmis:queryable>
</cmis:propertyStringDefinition>
<cmis:propertyStringDefinition>
<cmis:id>xbrl:entryPoint</cmis:id>
<cmis:localName>entryPoint</cmis:localName>
<cmis:displayName>Taxonomy Entry Point</cmis:displayName>
<cmis:queryName>xbrl:entryPoint</cmis:queryName>
<cmis:propertyType>string</cmis:propertyType>
<cmis:cardinality>single</cmis:cardinality>
<cmis:required>true</cmis:required>
</cmis:propertyStringDefinition>
<cmis:propertyStringDefinition>
<cmis:id>xbrl:completionStatus</cmis:id>
<cmis:localName>completionStatus</cmis:localName>
<cmis:displayName>Completion Status</cmis:displayName>
<cmis:queryName>xbrl:completionStatus</cmis:queryName>
<cmis:propertyType>string</cmis:propertyType>
<cmis:cardinality>single</cmis:cardinality>
<cmis:updatability>readwrite</cmis:updatability>
</cmis:propertyStringDefinition>
<!-- Additional XBRL-specific properties -->
</cmis:typeDefinition>
CMIS (Content Management Interoperability Services) is an OASIS standard for content management.
Standard CMIS Features:
Why extend CMIS for XBRL?
GLOMIDCO's CMIS Extension:
// Standard CMIS Document
interface Document {
String getId();
String getName();
byte[] getContent();
void setContent(byte[] content);
List<Version> getVersions();
}
// Extended XBRL Document
interface XBRLDocument extends Document {
// XBRL-specific metadata
TaxonomyReference getTaxonomy();
EntryPoint getEntryPoint();
String getReportingEntity();
LocalDate getReportingPeriod();
// Viewpoint support
List<Viewpoint> getAvailableViewpoints();
ViewpointContent getViewpoint(String viewpointId);
// Fact-level access
List<Fact> getFacts(String conceptFilter);
void updateFact(String factId, Object newValue);
void addFact(Fact fact);
void removeFact(String factId);
// Section-based editing
List<Section> getSections();
void lockSection(String sectionId, String userId);
void unlockSection(String sectionId);
boolean isSectionLocked(String sectionId);
// Validation
ValidationResult validatePartial(ValidationScope scope);
ValidationResult validateComplete();
CompletionStatus getCompletionStatus();
// Signing
void addSignature(XAdESSignature signature);
List<XAdESSignature> getSignatures();
boolean isFullySigned();
}
Key Innovations:
1. Multilayered Structure
XBRL Document (CMIS Object)
├─ Layer 1: Core XBRL (facts, contexts, units)
├─ Layer 2: Presentation (how to display)
├─ Layer 3: Viewpoints (different perspectives)
├─ Layer 4: Workflow metadata (status, locks, etc.)
└─ Layer 5: Signatures (XAdES digital signatures)
2. Section-Based Locking
// Define sections
Section balanceSheet = document.getSection("BalanceSheet");
Section taxDisclosures = document.getSection("TaxDisclosures");
Section auditOpinion = document.getSection("AuditOpinion");
// Tax specialist locks their section
taxDisclosures.lock("tax-specialist-user-id");
// Others can still view but not edit
ViewpointContent view = document.getViewpoint("TaxView");
// Can view
// Cannot edit tax section
// Controller tries to edit balance sheet
balanceSheet.lock("controller-user-id");
balanceSheet.updateFact("Assets", 1500000);
3. Viewpoint Management
// Define viewpoints
Viewpoint financialView = new Viewpoint("FinancialView");
financialView.includeSections("BalanceSheet", "IncomeStatement", "CashFlow");
financialView.setRole("Accountant");
Viewpoint taxView = new Viewpoint("TaxView");
taxView.includeSections("BalanceSheet", "TaxDisclosures");
taxView.setRole("TaxSpecialist");
Viewpoint auditView = new Viewpoint("AuditView");
auditView.includeSections("*"); // All sections
auditView.setRole("Auditor");
// Store in CMIS
document.registerViewpoint(financialView);
document.registerViewpoint(taxView);
document.registerViewpoint(auditView);
// Tax specialist gets their view
ViewpointContent content = document.getViewpoint("TaxView");
// Only sees relevant sections
Folder Organization:
CMIS Repository
├─ /annual-reports/
│ ├─ /2024/
│ │ ├─ /ACME-Corp/
│ │ │ ├─ jaarrekening-2024.xbrl (XBRL Document)
│ │ │ ├─ .metadata/
│ │ │ │ ├─ viewpoints.xml
│ │ │ │ ├─ sections.xml
│ │ │ │ ├─ workflow-state.xml
│ │ │ │ └─ validation-history.xml
│ │ │ └─ .versions/
│ │ │ ├─ v1-draft-accountant.xbrl
│ │ │ ├─ v2-with-tax.xbrl
│ │ │ ├─ v3-with-valuations.xbrl
│ │ │ └─ v4-final.xbrl
│ │ │
│ │ └─ /XYZ-Corp/
│ │ └─ ...
│ │
│ └─ /2023/
│ └─ ...
│
└─ /audit-reports/
└─ ...
Document Properties (CMIS Metadata):
{
"cmis:objectId": "xbrl-doc-12345",
"cmis:name": "jaarrekening-2024.xbrl",
"cmis:createdBy": "accountant-user",
"cmis:creationDate": "2024-01-15T10:00:00Z",
"cmis:lastModifiedBy": "tax-specialist",
"cmis:lastModificationDate": "2024-02-20T14:30:00Z",
"xbrl:taxonomy": "nl-fr-gaap-2024",
"xbrl:entryPoint": "jaarstukken-groot",
"xbrl:reportingEntity": "12345678",
"xbrl:reportingPeriod": "2024-12-31",
"xbrl:completionStatus": "60%",
"xbrl:validationStatus": "PARTIAL_VALID",
"xbrl:currentStage": "TAX_REVIEW",
"workflow:processInstanceId": "wf-98765",
"workflow:currentTask": "tax-specialist-review",
"workflow:assignedTo": "tax-specialist-user"
}
BPMN 2.0 Process for Annual Report Creation:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
<process id="jaarrekening-creation" name="Jaarrekening Creation Process">
<!-- Start Event -->
<startEvent id="start" name="Year End">
<outgoing>flow1</outgoing>
</startEvent>
<!-- Task 1: Accountant creates draft -->
<userTask id="accountant-draft" name="Create Financial Statements">
<incoming>flow1</incoming>
<outgoing>flow2</outgoing>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>role:Accountant</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
<extensionElements>
<glomidco:cmisDocument>jaarrekening-2024.xbrl</glomidco:cmisDocument>
<glomidco:viewpoint>FinancialView</glomidco:viewpoint>
<glomidco:sections>BalanceSheet,IncomeStatement,CashFlow</glomidco:sections>
<glomidco:validation>partial</glomidco:validation>
</extensionElements>
</userTask>
<!-- Parallel Gateway: Tax and Valuations can happen simultaneously -->
<parallelGateway id="parallel1">
<incoming>flow2</incoming>
<outgoing>flow3</outgoing>
<outgoing>flow4</outgoing>
</parallelGateway>
<!-- Task 2: Tax specialist adds tax data -->
<userTask id="tax-review" name="Add Tax Disclosures">
<incoming>flow3</incoming>
<outgoing>flow5</outgoing>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>role:TaxSpecialist</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
<extensionElements>
<glomidco:cmisDocument>jaarrekening-2024.xbrl</glomidco:cmisDocument>
<glomidco:viewpoint>TaxView</glomidco:viewpoint>
<glomidco:sections>TaxDisclosures</glomidco:sections>
<glomidco:lockSections>TaxDisclosures</glomidco:lockSections>
</extensionElements>
</userTask>
<!-- Task 3: Valuator reviews assets -->
<userTask id="asset-valuation" name="Update Asset Valuations">
<incoming>flow4</incoming>
<outgoing>flow6</outgoing>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>role:Valuator</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
<extensionElements>
<glomidco:cmisDocument>jaarrekening-2024.xbrl</glomidco:cmisDocument>
<glomidco:viewpoint>AssetView</glomidco:viewpoint>
<glomidco:sections>AssetValuations</glomidco:sections>
</extensionElements>
</userTask>
<!-- Join parallel paths -->
<parallelGateway id="parallel2">
<incoming>flow5</incoming>
<incoming>flow6</incoming>
<outgoing>flow7</outgoing>
</parallelGateway>
<!-- Service Task: Validate document -->
<serviceTask id="validation1" name="Validate Financial Data">
<incoming>flow7</incoming>
<outgoing>flow8</outgoing>
<extensionElements>
<glomidco:serviceCall>
<glomidco:service>ESB.validateXBRL</glomidco:service>
<glomidco:scope>FINANCIAL_DATA</glomidco:scope>
</glomidco:serviceCall>
</extensionElements>
</serviceTask>
<!-- Gateway: Validation passed? -->
<exclusiveGateway id="gateway1" name="Valid?">
<incoming>flow8</incoming>
<outgoing>flow9</outgoing>
<outgoing>flow10</outgoing>
</exclusiveGateway>
<!-- If failed, loop back to controller -->
<userTask id="controller-fix" name="Controller: Fix Errors">
<incoming>flow9</incoming>
<outgoing>flow11</outgoing>
</userTask>
<!-- Task 4: Auditor reviews -->
<userTask id="auditor-review" name="Auditor Review">
<incoming>flow10</incoming>
<incoming>flow11</incoming>
<outgoing>flow12</outgoing>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>role:Auditor</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
<extensionElements>
<glomidco:cmisDocument>jaarrekening-2024.xbrl</glomidco:cmisDocument>
<glomidco:viewpoint>AuditView</glomidco:viewpoint>
<glomidco:sections>*</glomidco:sections>
<glomidco:allowEdits>AuditOpinion</glomidco:allowEdits>
</extensionElements>
</userTask>
<!-- Service Task: Final validation -->
<serviceTask id="validation2" name="Final Validation">
<incoming>flow12</incoming>
<outgoing>flow13</outgoing>
<extensionElements>
<glomidco:serviceCall>
<glomidco:service>ESB.validateXBRL</glomidco:service>
<glomidco:scope>COMPLETE</glomidco:scope>
</glomidco:serviceCall>
</extensionElements>
</serviceTask>
<!-- Task 5: Board approval and signing -->
<userTask id="board-approval" name="Board Approval and Signing">
<incoming>flow13</incoming>
<outgoing>flow14</outgoing>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>role:CFO</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
<extensionElements>
<glomidco:cmisDocument>jaarrekening-2024.xbrl</glomidco:cmisDocument>
<glomidco:viewpoint>ExecutiveView</glomidco:viewpoint>
<glomidco:requireSignature>true</glomidco:requireSignature>
</extensionElements>
</userTask>
<!-- Service Task: Add XAdES signature -->
<serviceTask id="signing" name="Apply XAdES Signature">
<incoming>flow14</incoming>
<outgoing>flow15</outgoing>
<extensionElements>
<glomidco:serviceCall>
<glomidco:service>ESB.signXBRL</glomidco:service>
<glomidco:signatureType>XAdES-BES</glomidco:signatureType>
</glomidco:serviceCall>
</extensionElements>
</serviceTask>
<!-- End Event -->
<endEvent id="end" name="Filed">
<incoming>flow15</incoming>
</endEvent>
<!-- Sequence flows -->
<sequenceFlow id="flow1" sourceRef="start" targetRef="accountant-draft"/>
<sequenceFlow id="flow2" sourceRef="accountant-draft" targetRef="parallel1"/>
<sequenceFlow id="flow3" sourceRef="parallel1" targetRef="tax-review"/>
<sequenceFlow id="flow4" sourceRef="parallel1" targetRef="asset-valuation"/>
<sequenceFlow id="flow5" sourceRef="tax-review" targetRef="parallel2"/>
<sequenceFlow id="flow6" sourceRef="asset-valuation" targetRef="parallel2"/>
<sequenceFlow id="flow7" sourceRef="parallel2" targetRef="validation1"/>
<sequenceFlow id="flow8" sourceRef="validation1" targetRef="gateway1"/>
<sequenceFlow id="flow9" sourceRef="gateway1" targetRef="controller-fix">
<conditionExpression>validationFailed</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow10" sourceRef="gateway1" targetRef="auditor-review">
<conditionExpression>validationPassed</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow11" sourceRef="controller-fix" targetRef="auditor-review"/>
<sequenceFlow id="flow12" sourceRef="auditor-review" targetRef="validation2"/>
<sequenceFlow id="flow13" sourceRef="validation2" targetRef="board-approval"/>
<sequenceFlow id="flow14" sourceRef="board-approval" targetRef="signing"/>
<sequenceFlow id="flow15" sourceRef="signing" targetRef="end"/>
</process>
</definitions>
User Task Handler:
@Component
public class XBRLTaskHandler implements TaskListener {
@Autowired
private CMISXBRLRepository cmisRepository;
@Autowired
private XBRLViewpointService viewpointService;
@Override
public void execute(DelegateTask task) {
// Get CMIS document reference from process variables
String documentId = (String) task.getVariable("cmisDocumentId");
// Load XBRL document from CMIS
XBRLDocument document = cmisRepository.getDocument(documentId);
// Get viewpoint for this task
String viewpointId = task.getTaskDefinitionKey() + "View";
Viewpoint viewpoint = document.getViewpoint(viewpointId);
// Get sections this user can edit
List<String> editableSections =
getEditableSections(task.getTaskDefinitionKey());
// Lock editable sections for this user
for (String section : editableSections) {
document.lockSection(section, task.getAssignee());
}
// Generate viewpoint content for user
ViewpointContent content =
viewpointService.generateContent(document, viewpoint);
// Make available to user interface
task.setVariable("viewpointContent", content);
task.setVariable("editableSections", editableSections);
}
@Override
public void complete(DelegateTask task) {
String documentId = (String) task.getVariable("cmisDocumentId");
XBRLDocument document = cmisRepository.getDocument(documentId);
// Unlock sections
List<String> editableSections =
(List<String>) task.getVariable("editableSections");
for (String section : editableSections) {
document.unlockSection(section);
}
// Save changes
cmisRepository.save(document);
// Create new version
document.createVersion("Completed: " + task.getName());
}
}
User Task Handler:
@Component
public class XBRLTaskHandler implements TaskListener {
@Autowired
private CMISXBRLRepository cmisRepository;
@Autowired
private XBRLViewpointService viewpointService;
@Override
public void execute(DelegateTask task) {
// Get CMIS document reference from process variables
String documentId = (String) task.getVariable("cmisDocumentId");
// Load XBRL document from CMIS
XBRLDocument document = cmisRepository.getDocument(documentId);
// Get viewpoint for this task
String viewpointId = task.getTaskDefinitionKey() + "View";
Viewpoint viewpoint = document.getViewpoint(viewpointId);
// Get sections this user can edit
List<String> editableSections =
getEditableSections(task.getTaskDefinitionKey());
// Lock editable sections for this user
for (String section : editableSections) {
document.lockSection(section, task.getAssignee());
}
// Generate viewpoint content for user
ViewpointContent content =
viewpointService.generateContent(document, viewpoint);
// Make available to user interface
task.setVariable("viewpointContent", content);
task.setVariable("editableSections", editableSections);
}
@Override
public void complete(DelegateTask task) {
String documentId = (String) task.getVariable("cmisDocumentId");
XBRLDocument document = cmisRepository.getDocument(documentId);
// Unlock sections
List<String> editableSections =
(List<String>) task.getVariable("editableSections");
for (String section : editableSections) {
document.unlockSection(section);
}
// Save changes
cmisRepository.save(document);
// Create new version
document.createVersion("Completed: " + task.getName());
}
}
The beauty of CMIS: Same operations work across all three bindings!
Scenario: BPM system needs to access XBRL documents via CMIS
Option 1: Using AtomPub Binding (Java/Apache Chemistry)
// Apache Chemistry OpenCMIS client
import org.apache.chemistry.opencmis.client.api.*;
import org.apache.chemistry.opencmis.commons.SessionParameter;
public class CMISAtomPubClient {
private Session cmisSession;
public void connect() {
Map<String, String> parameters = new HashMap<>();
// AtomPub binding endpoint
parameters.put(SessionParameter.BINDING_TYPE,
BindingType.ATOMPUB.value());
parameters.put(SessionParameter.ATOMPUB_URL,
"http://cmis.example.com/cmis/atom");
parameters.put(SessionParameter.USER, "bpm-service");
parameters.put(SessionParameter.PASSWORD, "***");
parameters.put(SessionParameter.REPOSITORY_ID, "annual-reports");
SessionFactory factory = SessionFactoryImpl.newInstance();
cmisSession = factory.createSession(parameters);
}
public XBRLDocument getXBRLDocument(String documentId) {
// Get document via CMIS
Document cmisDoc = (Document) cmisSession.getObject(documentId);
// Access XBRL-specific properties
String taxonomy = cmisDoc.getPropertyValue("xbrl:taxonomy");
String entryPoint = cmisDoc.getPropertyValue("xbrl:entryPoint");
String completionStatus = cmisDoc.getPropertyValue("xbrl:completionStatus");
// Get content stream
ContentStream contentStream = cmisDoc.getContentStream();
byte[] xbrlContent = readStream(contentStream.getStream());
// Build XBRL document wrapper
XBRLDocument xbrlDoc = new XBRLDocument();
xbrlDoc.setId(documentId);
xbrlDoc.setTaxonomy(taxonomy);
xbrlDoc.setEntryPoint(entryPoint);
xbrlDoc.setCompletionStatus(completionStatus);
xbrlDoc.setContent(xbrlContent);
return xbrlDoc;
}
public void lockSection(String documentId, String sectionId, String userId) {
Document doc = (Document) cmisSession.getObject(documentId);
// Get current locked sections (stored as JSON)
String lockedSectionsJson = doc.getPropertyValue("xbrl:lockedSections");
Map<String, String> lockedSections =
parseJson(lockedSectionsJson, Map.class);
// Add lock
lockedSections.put(sectionId, userId);
// Update property
Map<String, Object> properties = new HashMap<>();
properties.put("xbrl:lockedSections", toJson(lockedSections));
doc.updateProperties(properties);
}
}
Option 2: Using SOAP Binding (.NET/C#)
using System;
using System.ServiceModel;
using CMIS.WebServices;
public class CMISSOAPClient
{
private ObjectServicePortClient objectService;
private RepositoryServicePortClient repositoryService;
public void Connect()
{
// SOAP binding endpoints
var objectEndpoint = new EndpointAddress(
"http://cmis.example.com/cmis/services/ObjectService");
var repoEndpoint = new EndpointAddress(
"http://cmis.example.com/cmis/services/RepositoryService");
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.MaxReceivedMessageSize = 10485760; // 10MB
objectService = new ObjectServicePortClient(binding, objectEndpoint);
repositoryService = new RepositoryServicePortClient(binding, repoEndpoint);
// Set credentials
objectService.ClientCredentials.UserName.UserName = "bpm-service";
objectService.ClientCredentials.UserName.Password = "***";
}
public XBRLDocument GetXBRLDocument(string documentId)
{
// Call SOAP service
var request = new getObjectRequest
{
repositoryId = "annual-reports",
objectId = documentId
};
var response = objectService.getObject(request);
var cmisObject = response.@object;
// Extract XBRL properties
var properties = cmisObject.properties.Items;
var taxonomy = GetProperty(properties, "xbrl:taxonomy");
var entryPoint = GetProperty(properties, "xbrl:entryPoint");
var completionStatus = GetProperty(properties, "xbrl:completionStatus");
// Build XBRL document
var xbrlDoc = new XBRLDocument
{
Id = documentId,
Taxonomy = taxonomy,
EntryPoint = entryPoint,
CompletionStatus = completionStatus
};
return xbrlDoc;
}
public void LockSection(string documentId, string sectionId, string userId)
{
// Get current document
var getRequest = new getObjectRequest
{
repositoryId = "annual-reports",
objectId = documentId
};
var getResponse = objectService.getObject(getRequest);
// Parse locked sections
var lockedSectionsJson = GetProperty(
getResponse.@object.properties.Items,
"xbrl:lockedSections");
var lockedSections = JsonConvert.DeserializeObject<Dictionary<string, string>>(
lockedSectionsJson);
// Add lock
lockedSections[sectionId] = userId;
// Update via SOAP
var updateRequest = new updatePropertiesRequest
{
repositoryId = "annual-reports",
objectId = documentId,
properties = new cmisPropertiesType
{
Items = new[]
{
new cmisPropertyString
{
propertyDefinitionId = "xbrl:lockedSections",
value = new[] { JsonConvert.SerializeObject(lockedSections) }
}
}
}
};
objectService.updateProperties(updateRequest);
}
}
Option 3: Using Browser/JSON Binding (JavaScript/Node.js)
// Node.js with axios
const axios = require('axios');
class CMISBrowserClient {
constructor(baseUrl, username, password) {
this.baseUrl = baseUrl;
this.auth = {
username: username,
password: password
};
}
async getXBRLDocument(documentId) {
// Browser/JSON binding request
const response = await axios.get(
`${this.baseUrl}/cmis/browser/root`,
{
auth: this.auth,
params: {
objectId: documentId,
cmisselector: 'object',
succinct: true
}
}
);
const cmisObject = response.data;
const props = cmisObject.succinctProperties;
// Extract XBRL properties
const xbrlDoc = {
id: props['cmis:objectId'],
name: props['cmis:name'],
taxonomy: props['xbrl:taxonomy'],
entryPoint: props['xbrl:entryPoint'],
reportingEntity: props['xbrl:reportingEntity'],
reportingPeriod: props['xbrl:reportingPeriod'],
completionStatus: props['xbrl:completionStatus'],
validationStatus: props['xbrl:validationStatus'],
currentStage: props['xbrl:currentStage']
};
return xbrlDoc;
}
async getXBRLContent(documentId) {
// Get content stream
const response = await axios.get(
`${this.baseUrl}/cmis/browser/root`,
{
auth: this.auth,
params: {
objectId: documentId,
cmisselector: 'content'
},
responseType: 'arraybuffer'
}
);
return response.data;
}
async lockSection(documentId, sectionId, userId) {
// Get current document
const doc = await this.getXBRLDocument(documentId);
// Parse locked sections
const lockedSectionsJson = doc.lockedSections || '{}';
const lockedSections = JSON.parse(lockedSectionsJson);
// Add lock
lockedSections[sectionId] = userId;
// Update via POST (Browser binding)
await axios.post(
`${this.baseUrl}/cmis/browser/root`,
new URLSearchParams({
objectId: documentId,
cmisaction: 'update',
'propertyId[0]': 'xbrl:lockedSections',
'propertyValue[0]': JSON.stringify(lockedSections)
}),
{
auth: this.auth,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
}
async queryXBRLDocuments(stage) {
// CMIS Query via Browser binding
const response = await axios.post(
`${this.baseUrl}/cmis/browser`,
new URLSearchParams({
cmisaction: 'query',
statement: `
SELECT cmis:objectId, cmis:name, xbrl:completionStatus
FROM xbrl:document
WHERE xbrl:currentStage = '${stage}'
`
}),
{
auth: this.auth,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
return response.data.results;
}
}
// Usage in BPM integration
const cmis = new CMISBrowserClient(
'http://cmis.example.com',
'bpm-service',
'***'
);
// BPM task handler
async function onTaskAssigned(taskId, documentId, userId) {
// Get XBRL document
const xbrlDoc = await cmis.getXBRLDocument(documentId);
// Lock appropriate section based on task
const section = getSectionForTask(taskId);
await cmis.lockSection(documentId, section, userId);
console.log(`Locked section ${section} for user ${userId}`);
}
async function onTaskCompleted(taskId, documentId) {
// Get document
const xbrlDoc = await cmis.getXBRLDocument(documentId);
// Unlock section
const section = getSectionForTask(taskId);
await cmis.lockSection(documentId, section, null);
// Update stage
await updateDocumentStage(documentId, getNextStage(xbrlDoc.currentStage));
console.log(`Task ${taskId} completed, document moved to next stage`);
}
Cross-Platform Integration Example:
┌──────────────────────────────────────────────┐
│ Enterprise Architecture │
├──────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ │
│ │ BPM System │ │
│ │ (Camunda/Java) │──AtomPub───┐ │
│ └────────────────┘ │ │
│ │ │
│ ┌────────────────┐ ▼ │
│ │ ESB Layer │ ┌─────────┐ │
│ │ (.NET/C#) │──SOAP───┤ CMIS │ │
│ └────────────────┘ │ Repo │ │
│ │ │ │
│ ┌────────────────┐ │(Alfresco│ │
│ │ Web UI │ │FileNet │ │
│ │ (React/Node) │──JSON───│etc.) │ │
│ └────────────────┘ └─────────┘ │
│ │
│ All accessing the SAME XBRL documents! │
│ All using the SAME CMIS standard! │
└──────────────────────────────────────────────┘
Major BPM platforms with CMIS support (as of 2014-2024):
Overview:
CMIS Integration:
// Activiti native CMIS support
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
public class ActivitiCMISExample {
@Autowired
private RuntimeService runtimeService;
public void startXBRLWorkflow(String cmisDocumentId) {
Map<String, Object> variables = new HashMap<>();
// CMIS document reference
variables.put("cmisDocumentId", cmisDocumentId);
variables.put("cmisRepositoryId", "annual-reports");
// Start process
ProcessInstance instance = runtimeService.startProcessInstanceByKey(
"jaarrekening-creation",
variables
);
}
}
Key Features:
CMIS Configuration:
<!-- Activiti CMIS Configuration -->
<bean id="cmisRepository" class="org.activiti.engine.impl.repository.CmisRepository">
<property name="id" value="annual-reports"/>
<property name="cmisAtomPubUrl" value="http://cmis.example.com/cmis/atom"/>
<property name="user" value="activiti-service"/>
<property name="password" value="***"/>
</bean>
Use Case Fit:
GLOMIDCO Integration:
// Service task calling GLOMIDCO via CMIS document
<serviceTask id="validateXBRL"
name="Validate XBRL Document"
activiti:delegateExpression="${xbrlValidationDelegate}">
<extensionElements>
<activiti:field name="cmisDocumentId">
<activiti:expression>${cmisDocumentId}</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>
Overview:
CMIS Integration:
// Camunda CMIS connector
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.connect.Connectors;
public class CamundaCMISDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
String documentId = (String) execution.getVariable("documentId");
// Use Camunda Connect for CMIS
Map<String, Object> cmisObject = Connectors.http()
.get()
.url("http://cmis.example.com/cmis/browser/root")
.payload("objectId=" + documentId + "&cmisselector=object")
.execute()
.getResponse();
// Process XBRL document
String taxonomy = (String) cmisObject.get("xbrl:taxonomy");
execution.setVariable("taxonomy", taxonomy);
}
}
Key Features:
CMIS Connector Configuration:
<!-- Camunda CMIS Service Task -->
<bpmn:serviceTask id="loadXBRL" name="Load XBRL Document">
<bpmn:extensionElements>
<camunda:connector>
<camunda:inputOutput>
<camunda:inputParameter name="url">
http://cmis.example.com/cmis/browser/root
</camunda:inputParameter>
<camunda:inputParameter name="method">GET</camunda:inputParameter>
<camunda:inputParameter name="headers">
<camunda:map>
<camunda:entry key="Accept">application/json</camunda:entry>
</camunda:map>
</camunda:inputParameter>
<camunda:inputParameter name="payload">
objectId=${documentId}&cmisselector=object
</camunda:inputParameter>
<camunda:outputParameter name="xbrlDocument">
${response}
</camunda:outputParameter>
</camunda:inputOutput>
<camunda:connectorId>http-connector</camunda:connectorId>
</camunda:connector>
</bpmn:extensionElements>
</bpmn:serviceTask>
Use Case Fit:
GLOMIDCO Integration Pattern:
Camunda Process
├─ Load XBRL from CMIS (HTTP connector)
├─ Call GLOMIDCO via ESB (External task)
├─ Update CMIS document (HTTP connector)
└─ Continue workflow
Overview:
CMIS Integration:
// Native integration - Alfresco IS the CMIS repository
import com.activiti.content.storage.api.ContentObject;
import com.activiti.service.api.ContentService;
@Service
public class AlfrescoXBRLService {
@Autowired
private ContentService contentService;
public void attachXBRLToProcess(String processInstanceId, String cmisDocumentId) {
// Direct integration - no external CMIS client needed
ContentObject xbrlDocument = contentService.getContentObject(cmisDocumentId);
// Attach to process
contentService.createRelatedContent(
processInstanceId,
cmisDocumentId,
"xbrl-document",
null
);
}
public XBRLDocument getXBRLFromProcess(String processInstanceId) {
// Get related CMIS content
List<ContentObject> relatedContent =
contentService.getRelatedContent(processInstanceId);
// Find XBRL document
ContentObject xbrlContent = relatedContent.stream()
.filter(c -> "xbrl-document".equals(c.getContentType()))
.findFirst()
.orElse(null);
// Content is already in CMIS repository
return parseXBRL(xbrlContent.getContent());
}
}
Key Features:
Architecture:
┌────────────────────────────────────────┐
│ Alfresco Process Services │
│ ├─ Process Engine (Activiti) │
│ └─ Content Services (CMIS Repository) │
│ └─ XBRL Documents stored here │
└────────────────────────────────────────┘
No external CMIS needed!
BPM and Content Management unified!
Use Case Fit:
GLOMIDCO Integration:
// Process calls GLOMIDCO with CMIS document reference
@Component
public class AlfrescoXBRLValidator implements JavaDelegate {
@Autowired
private ContentService contentService;
@Autowired
private GLOMIDCOService glomidco;
@Override
public void execute(DelegateExecution execution) {
String documentId = (String) execution.getVariable("cmisDocumentId");
// Get content from Alfresco CMIS repository
ContentObject content = contentService.getContentObject(documentId);
byte[] xbrlData = content.getContent();
// Validate with GLOMIDCO
ValidationResult result = glomidco.validate(xbrlData);
// Store result back in CMIS properties
Map<String, Object> properties = new HashMap<>();
properties.put("xbrl:validationStatus", result.getStatus());
properties.put("xbrl:validationDate", new Date());
contentService.updateContentProperties(documentId, properties);
execution.setVariable("validationResult", result);
}
}
Overview:
CMIS Integration:
// IBM FileNet CMIS integration
import com.ibm.filenet.api.*;
import com.ibm.filenet.api.core.*;
import org.apache.chemistry.opencmis.client.api.*;
public class IBMFileNetCMISIntegration {
public void integrateWithBPM(String cmisDocumentId) {
// FileNet is CMIS-compliant
Map<String, String> parameters = new HashMap<>();
parameters.put(SessionParameter.BINDING_TYPE,
BindingType.WEBSERVICES.value());
parameters.put(SessionParameter.WEBSERVICES_WSDL_SERVICE,
"http://filenet.example.com/wsi/FNCEWS40MTOM/");
parameters.put(SessionParameter.REPOSITORY_ID, "ObjectStore");
SessionFactory factory = SessionFactoryImpl.newInstance();
Session session = factory.createSession(parameters);
// Get XBRL document
Document doc = (Document) session.getObject(cmisDocumentId);
// FileNet specific properties for XBRL
String taxonomy = doc.getPropertyValue("XBRL_Taxonomy");
String validationStatus = doc.getPropertyValue("XBRL_ValidationStatus");
}
}
Key Features:
BPM Integration:
<!-- IBM BPM Coach (UI) with CMIS document -->
<coach>
<variables>
<variable name="cmisDocumentId" type="String"/>
<variable name="xbrlDocument" type="ECMDocument"/>
</variables>
<contentType>
<ECMServer>FileNet</ECMServer>
<ECMRepository>ObjectStore</ECMRepository>
<DocumentClass>XBRL_Document</DocumentClass>
</contentType>
</coach>
Use Case Fit:
Overview:
CMIS Integration:
// Pega REST connector to CMIS
{
"connectorName": "CMIS_XBRLRepository",
"connectorType": "REST",
"baseURL": "http://cmis.example.com/cmis/browser",
"authentication": "Basic",
"methods": [
{
"name": "getXBRLDocument",
"httpMethod": "GET",
"path": "/root",
"parameters": [
{
"name": "objectId",
"type": "query",
"required": true
},
{
"name": "cmisselector",
"type": "query",
"value": "object"
}
],
"response": {
"type": "JSON",
"mapping": {
"documentId": "$.succinctProperties['cmis:objectId']",
"taxonomy": "$.succinctProperties['xbrl:taxonomy']",
"completionStatus": "$.succinctProperties['xbrl:completionStatus']"
}
}
}
]
}
Key Features:
Use Case Fit:
Overview:
CMIS Integration:
// jBPM work item handler for CMIS
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;
public class CMISWorkItemHandler implements WorkItemHandler {
private Session cmisSession;
@Override
public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
String documentId = (String) workItem.getParameter("documentId");
String operation = (String) workItem.getParameter("operation");
Map<String, Object> results = new HashMap<>();
switch (operation) {
case "GET":
Document doc = (Document) cmisSession.getObject(documentId);
results.put("xbrlDocument", doc);
results.put("taxonomy", doc.getPropertyValue("xbrl:taxonomy"));
break;
case "UPDATE":
Document doc = (Document) cmisSession.getObject(documentId);
Map<String, Object> props = new HashMap<>();
props.put("xbrl:validationStatus", workItem.getParameter("validationStatus"));
doc.updateProperties(props);
break;
case "LOCK_SECTION":
// Custom CMIS extension
lockSection(documentId,
(String) workItem.getParameter("sectionId"),
(String) workItem.getParameter("userId"));
break;
}
manager.completeWorkItem(workItem.getId(), results);
}
}
Key Features:
Use Case Fit:
Overview:
CMIS Integration:
// Bonita connector for CMIS
import org.bonitasoft.engine.connector.AbstractConnector;
import org.apache.chemistry.opencmis.client.api.*;
class CMISConnector extends AbstractConnector {
@Override
void executeBusinessLogic() {
String documentId = getInputParameter("documentId");
String repositoryUrl = getInputParameter("repositoryUrl");
// Connect to CMIS
Session session = createCMISSession(repositoryUrl);
// Get XBRL document
Document doc = (Document) session.getObject(documentId);
// Set output parameters
setOutputParameter("taxonomy", doc.getPropertyValue("xbrl:taxonomy"));
setOutputParameter("completionStatus", doc.getPropertyValue("xbrl:completionStatus"));
}
Session createCMISSession(String url) {
Map<String, String> parameters = new HashMap<>();
parameters.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
parameters.put(SessionParameter.ATOMPUB_URL, url);
// ... authentication
return SessionFactoryImpl.newInstance().createSession(parameters);
}
}
Key Features:
Use Case Fit:
CMIS Integration Capabilities:
Platform | CMIS Binding | Native | Integration | Enterprise | Cost |
| Support | Repo | Effort | Support | |
────────────────────────────────────────────────────────────────────────────────────────
Activiti | AtomPub, SOAP | No | Medium | Community | Free |
Camunda | HTTP/REST | No | Medium | Optional | Free/Paid |
Alfresco Process | All (Native) | Yes | Low | Yes | Paid |
IBM BAW | SOAP, WS | Yes | Low | Yes | Expensive |
Pega | REST | No | Low | Yes | Expensive |
jBPM | Custom | No | High | Red Hat | Free/Paid |
Bonita | Custom | No | Medium | Optional | Free/Paid |
────────────────────────────────────────────────────────────────────────────────────────
Legend:
Native Repo: Has built-in CMIS-compliant repository
Integration Effort: Development work needed
Recommended Combinations for XBRL:
Scenario | Recommended BPM | CMIS Repository |
──────────────────────────────────────────────────────────────────────────────
Small company, budget-conscious | Activiti | Alfresco Community |
Medium company, modern stack | Camunda | Alfresco |
Document-heavy workflows | Alfresco Process | Alfresco (native) |
Large enterprise, IBM shop | IBM BAW | FileNet (native) |
Low-code requirement | Pega | Any CMIS repo |
Cloud-native architecture | jBPM | AWS S3 + CMIS |
Portal requirement | Bonita | Nuxeo |
──────────────────────────────────────────────────────────────────────────────
GLOMIDCO Compatibility:
All platforms above work with GLOMIDCO's BPM/CMIS/ESB architecture because:
Selection Criteria for XBRL Workflows:
Already have ECM?
Budget?
Team Skills?
Cloud Strategy?
XBRL Volume?
The Bottom Line:
For XBRL workflows with GLOMIDCO:
Enterprise Service Bus provides services for:
┌────────────────────────────────────────────┐
│ ESB Services (Mule ESB, WSO2, Tibco, etc) │
├────────────────────────────────────────────┤
│ │
│ 1. XBRL Validation Service │
│ ├─ Partial validation │
│ ├─ Complete validation │
│ └─ Validation scopes │
│ │
│ 2. Viewpoint Generation Service │
│ ├─ Generate HTML view │
│ ├─ Generate PDF view │
│ └─ Generate section view │
│ │
│ 3. XAdES Signing Service │
│ ├─ Sign complete document │
│ ├─ Sign specific sections │
│ └─ Verify signatures │
│ │
│ 4. Schema Generation Service │
│ ├─ Generate JSON Schema │
│ ├─ Generate XSD │
│ └─ Generate for viewpoint │
│ │
│ 5. Transformation Service │
│ ├─ XBRL-XML ↔ xBRL-JSON │
│ ├─ XBRL-XML ↔ xBRL-CSV │
│ └─ Extract to formats │
│ │
│ 6. Notification Service │
│ ├─ Validation errors │
│ ├─ Task assignments │
│ └─ Approval requests │
│ │
└────────────────┬───────────────────────────┘
│
│ All services use
▼
┌────────────────────────────────────────────┐
│ GLOMIDCO XBRL Processor │
│ (Three-phase architecture) │
└────────────────────────────────────────────┘
Progressive Validation Implementation:
@RestController
@RequestMapping("/xbrl/validation")
public class XBRLValidationService {
@Autowired
private GLOMIDCOProcessor processor;
@Autowired
private CMISXBRLRepository repository;
@PostMapping("/validate")
public ValidationResult validate(
@RequestParam String documentId,
@RequestParam ValidationScope scope) {
// Load document from CMIS
XBRLDocument document = repository.getDocument(documentId);
// Get current completion status
CompletionStatus status = document.getCompletionStatus();
// Configure validation based on scope and status
ValidationConfig config = new ValidationConfig();
switch (scope) {
case PARTIAL:
// Validate only what's present
config.setRequiredFactsCheck(false);
config.setCalculationCheck(true);
config.setDimensionalCheck(true);
config.setFormulaCheck(false); // May depend on missing facts
break;
case SECTION:
// Validate specific section
String sectionId = document.getCurrentEditSection();
config.setSectionFilter(sectionId);
config.setRequiredFactsCheck(false);
config.setCalculationCheck(true);
break;
case COMPLETE:
// Full validation
config.setRequiredFactsCheck(true);
config.setCalculationCheck(true);
config.setDimensionalCheck(true);
config.setFormulaCheck(true);
break;
}
// Validate using GLOMIDCO processor
ValidationResult result =
processor.validate(document.getXBRLContent(), config);
// Enrich with completion information
if (scope == ValidationScope.COMPLETE && !result.isValid()) {
// Check if errors are due to incompleteness
List<ValidationError> missingFactErrors =
result.getErrors().stream()
.filter(e -> e.getType() == ErrorType.MISSING_REQUIRED_FACT)
.collect(Collectors.toList());
if (!missingFactErrors.isEmpty()) {
result.setStatus(ValidationStatus.INCOMPLETE);
result.setMessage(
"Document incomplete. Missing " +
missingFactErrors.size() + " required facts.");
}
}
// Store validation result in CMIS
document.addValidationResult(result);
repository.save(document);
return result;
}
@GetMapping("/required-facts")
public List<RequiredFact> getRequiredFacts(
@RequestParam String documentId) {
XBRLDocument document = repository.getDocument(documentId);
// Use processor to determine required facts based on taxonomy
List<RequiredFact> required =
processor.getRequiredFacts(
document.getTaxonomy(),
document.getEntryPoint()
);
// Check which are present
Set<String> presentConcepts = document.getFacts().stream()
.map(Fact::getConcept)
.collect(Collectors.toSet());
// Mark as present or missing
required.forEach(fact -> {
fact.setPresent(presentConcepts.contains(fact.getConcept()));
});
return required;
}
}
Digital Signature Integration:
@RestController
@RequestMapping("/xbrl/signing")
public class XAdESSigningService {
@Autowired
private XAdESSignatureProvider signatureProvider;
@Autowired
private CMISXBRLRepository repository;
@PostMapping("/sign")
public SignatureResult sign(
@RequestParam String documentId,
@RequestParam String signerCertificate,
@RequestParam SignatureType signatureType) {
// Load document
XBRLDocument document = repository.getDocument(documentId);
// Validate before signing
ValidationResult validation =
validateBeforeSigning(document);
if (!validation.isValid()) {
throw new SignatureException(
"Document must be valid before signing: " +
validation.getErrors());
}
// Create XAdES signature
XAdESSignature signature =
signatureProvider.createSignature(
document.getXBRLContent(),
signerCertificate,
signatureType
);
// Add signature to document
document.addSignature(signature);
// Mark sections as signed (immutable)
document.markAsSigned();
// Save
repository.save(document);
return new SignatureResult(
signature.getSignatureId(),
signature.getTimestamp(),
signature.getSignerInfo()
);
}
@GetMapping("/verify")
public VerificationResult verify(
@RequestParam String documentId) {
XBRLDocument document = repository.getDocument(documentId);
List<XAdESSignature> signatures = document.getSignatures();
List<SignatureVerification> verifications = new ArrayList<>();
for (XAdESSignature signature : signatures) {
SignatureVerification verification =
signatureProvider.verify(
document.getXBRLContent(),
signature
);
verifications.add(verification);
}
return new VerificationResult(verifications);
}
}
@RestController
@RequestMapping("/xbrl/viewpoint")
public class ViewpointGenerationService {
@Autowired
private GLOMIDCOProcessor processor;
@Autowired
private CMISXBRLRepository repository;
@PostMapping("/generate")
public ViewpointContent generateViewpoint(
@RequestParam String documentId,
@RequestParam String viewpointId,
@RequestParam OutputFormat format) {
// Load document and viewpoint
XBRLDocument document = repository.getDocument(documentId);
Viewpoint viewpoint = document.getViewpoint(viewpointId);
// Filter facts based on viewpoint sections
List<Fact> relevantFacts = filterFacts(
document.getFacts(),
viewpoint.getIncludedSections()
);
// Generate content based on format
ViewpointContent content = null;
switch (format) {
case HTML:
content = processor.renderAsHTML(
relevantFacts,
viewpoint.getPresentationStructure()
);
break;
case PDF:
content = processor.renderAsPDF(
relevantFacts,
viewpoint.getPresentationStructure()
);
break;
case JSON:
content = processor.renderAsJSON(relevantFacts);
break;
case INLINE_XBRL:
content = processor.renderAsInlineXBRL(
relevantFacts,
viewpoint.getPresentationStructure()
);
break;
}
// Cache for future requests
document.cacheViewpointContent(viewpointId, format, content);
repository.save(document);
return content;
}
}
Angular/React Component Architecture:
// XBRLDocumentEditor Component
@Component({
selector: 'xbrl-document-editor',
template: `
<div class="xbrl-editor">
<!-- Header with document info -->
<div class="header">
<h2>{{document.name}}</h2>
<div class="status">
<span>Completion: {{document.completionStatus}}%</span>
<span>Stage: {{document.currentStage}}</span>
</div>
</div>
<!-- Navigation tabs -->
<div class="tabs">
<button *ngFor="let section of availableSections"
(click)="selectSection(section)"
[class.active]="currentSection === section"
[disabled]="!canEditSection(section)">
{{section.name}}
<span *ngIf="section.locked" class="lock-icon">🔒</span>
</button>
</div>
<!-- Content area -->
<div class="content">
<!-- Viewpoint selector -->
<div class="viewpoint-selector">
<label>View as:</label>
<select [(ngModel)]="selectedViewpoint"
(change)="loadViewpoint()">
<option *ngFor="let vp of viewpoints"
[value]="vp.id">
{{vp.name}}
</option>
</select>
</div>
<!-- Rendered content -->
<div class="rendered-content"
[innerHTML]="viewpointContent">
</div>
<!-- Fact editor (for editable sections) -->
<div *ngIf="canEditSection(currentSection)"
class="fact-editor">
<xbrl-fact-editor
[facts]="editableFacts"
[schema]="sectionSchema"
(factChanged)="onFactChanged($event)">
</xbrl-fact-editor>
</div>
</div>
<!-- Actions -->
<div class="actions">
<button (click)="validateSection()"
[disabled]="!hasChanges">
Validate Section
</button>
<button (click)="saveChanges()"
[disabled]="!hasChanges || validationErrors.length > 0">
Save Changes
</button>
<button (click)="completeTask()">
Complete Task
</button>
</div>
<!-- Validation results -->
<div *ngIf="validationErrors.length > 0"
class="validation-errors">
<h3>Validation Errors:</h3>
<ul>
<li *ngFor="let error of validationErrors"
[class.error]="error.severity === 'ERROR'"
[class.warning]="error.severity === 'WARNING'">
{{error.message}}
</li>
</ul>
</div>
</div>
`
})
export class XBRLDocumentEditor implements OnInit {
@Input() documentId: string;
@Input() taskId: string;
document: XBRLDocument;
viewpoints: Viewpoint[];
selectedViewpoint: string;
viewpointContent: SafeHtml;
availableSections: Section[];
currentSection: Section;
editableFacts: Fact[];
sectionSchema: JsonSchema;
hasChanges: boolean = false;
validationErrors: ValidationError[] = [];
constructor(
private cmisService: CMISService,
private esbService: ESBService,
private bpmService: BPMService,
private sanitizer: DomSanitizer
) {}
ngOnInit() {
this.loadDocument();
}
async loadDocument() {
// Load from CMIS
this.document = await this.cmisService.getDocument(this.documentId);
// Get available viewpoints
this.viewpoints = this.document.viewpoints;
// Get editable sections for this task
const task = await this.bpmService.getTask(this.taskId);
this.availableSections = task.editableSections;
// Load default viewpoint
this.selectedViewpoint = task.defaultViewpoint;
await this.loadViewpoint();
}
async loadViewpoint() {
// Call ESB to generate viewpoint content
const content = await this.esbService.generateViewpoint(
this.documentId,
this.selectedViewpoint,
'HTML'
);
this.viewpointContent = this.sanitizer.bypassSecurityTrustHtml(content);
}
async selectSection(section: Section) {
this.currentSection = section;
// Load facts for this section
this.editableFacts = await this.cmisService.getSectionFacts(
this.documentId,
section.id
);
// Get schema for this section
this.sectionSchema = await this.esbService.generateSectionSchema(
this.document.taxonomy,
this.document.entryPoint,
section.id
);
}
canEditSection(section: Section): boolean {
return !section.locked || section.lockedBy === this.getCurrentUser();
}
onFactChanged(event: FactChangeEvent) {
this.hasChanges = true;
// Update fact in memory
const fact = this.editableFacts.find(f => f.id === event.factId);
if (fact) {
fact.value = event.newValue;
}
}
async validateSection() {
this.validationErrors = await this.esbService.validateSection(
this.documentId,
this.currentSection.id
);
}
async saveChanges() {
try {
// Save to CMIS
await this.cmisService.updateFacts(
this.documentId,
this.editableFacts
);
this.hasChanges = false;
// Reload viewpoint to show updated data
await this.loadViewpoint();
// Show success message
this.showMessage('Changes saved successfully');
} catch (error) {
this.showError('Failed to save changes: ' + error.message);
}
}
async completeTask() {
// Validate before completing
const validation = await this.esbService.validateSection(
this.documentId,
this.currentSection.id
);
if (validation.hasErrors) {
this.showError('Cannot complete task: validation errors exist');
return;
}
// Complete BPM task
await this.bpmService.completeTask(this.taskId);
// Navigate away
this.router.navigate(['/tasks']);
}
}
Concept: Real-time collaborative editing like Google Docs
Approach:
┌─────────────────────────────────────────┐
│ Web Application │
│ ├─ Real-time fact editing │
│ ├─ Operational transformation │
│ ├─ Conflict resolution │
│ └─ Live presence indicators │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ WebSocket Server │
│ ├─ Broadcast fact changes │
│ ├─ Lock management │
│ └─ Conflict detection │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ XBRL Document Store │
│ ├─ Fact-level versioning │
│ ├─ Change log │
│ └─ Merge strategies │
└─────────────────────────────────────────┘
Pros:
Cons:
Concept: Treat XBRL like source code
Approach:
git repository/
├─ jaarrekening-2024.xbrl (main document)
├─ sections/
│ ├─ balance-sheet.xml
│ ├─ income-statement.xml
│ ├─ tax-disclosures.xml
│ └─ audit-opinion.xml
└─ .xbrl/
├─ taxonomy.ref
└─ validation.config
Workflow:
1. Accountant: git checkout -b accountant-draft
2. Make changes
3. git commit -m "Added balance sheet facts"
4. git push
5. Create pull request
6. Controller reviews
7. git merge
Pros:
Cons:
Concept: Edit XBRL as spreadsheets (xBRL-CSV)
Approach:
Excel/Google Sheets
├─ Sheet 1: Balance Sheet
│ Concept | Value | Period |
│ ──────────────────────────────────────────────────
│ Assets | 1000000 | 2024-12-31 |
│ Liabilities | 600000 | 2024-12-31 |
│
├─ Sheet 2: Tax Disclosures
│ Concept | Value | Period |
│ ──────────────────────────────────────────────────
│ TaxExpense | 50000 | 2024 |
│ DeferredTaxAssets | 20000 | 2024-12-31 |
│
└─ On Save: Convert to XBRL
Pros:
Cons:
Concept: Web forms for each section
Approach:
Web Form: Balance Sheet Section
┌──────────────────────────────────────┐
│ Assets │
├──────────────────────────────────────┤
│ Cash and Cash Equivalents: │
│ [ 1,000,000 ] EUR │
│ │
│ Accounts Receivable: │
│ [ 500,000 ] EUR │
│ │
│ Inventory: │
│ [ 300,000 ] EUR │
│ │
│ Property, Plant & Equipment: │
│ [ 2,000,000 ] EUR │
│ │
│ Total Assets (calculated): │
│ 3,800,000 EUR ✓ │
│ │
│ [Validate Section] [Save] [Next] │
└──────────────────────────────────────┘
Pros:
Cons:
What Works:
CMIS Extension Approach
BPM-Driven Workflow
ESB Service Layer
Viewpoint-Based Access
Progressive Validation
What Doesn't Work:
❌ File-Based Sharing
❌ Monolithic Editing
❌ Late Validation
❌ No Version Control
For Organizations Implementing Collaborative XBRL:
Phase 1: Foundation (3 months)
1. Choose BPM platform (Camunda, Activiti, etc.)
2. Set up CMIS repository (Alfresco, FileNet, etc.)
3. Implement CMIS extension for XBRL
4. Define basic viewpoints
5. Integrate GLOMIDCO processor
Phase 2: ESB Services (2 months)
1. Implement validation service
2. Implement viewpoint generation service
3. Implement signing service (if needed)
4. Create service registry
5. Document APIs
Phase 3: Workflow Design (2 months)
1. Map business process to BPMN
2. Define task forms
3. Configure task assignments
4. Set up approval flows
5. Test end-to-end
Phase 4: User Interface (3 months)
1. Design viewpoint-based editor
2. Implement fact editing
3. Integrate validation feedback
4. Add inline help
5. User acceptance testing
Phase 5: Production Rollout (2 months)
1. Pilot with small group
2. Gather feedback
3. Refine workflows
4. Train users
5. Go live
Total: 12 months typical implementation
Access Control Matrix:
Role | View All | Edit Financial | Edit Tax | Edit Audit | Approve | Sign |
──────────────────────────────────────────────────────────────────────────────────────
Accountant | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
Tax Specialist | ✓ | ✗ | ✓ | ✗ | ✗ | ✗ |
Controller | ✓ | ✓ | ✓ | ✗ | ✓ | ✗ |
Auditor | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ |
CFO | ✓ | ✗ | ✗ | ✗ | ✓ | ✓ |
Audit Requirements:
Regulatory Requirements:
XBRL documents are NOT created atomically:
Traditional file-based approaches fail:
BPM + CMIS + ESB + GLOMIDCO Processor:
Key Innovations:
GLOMIDCO architecture is one proven solution, but others exist:
Choose based on:
Creating XBRL documents collaboratively is complex, but solvable.
GLOMIDCO's approach provides:
For organizations implementing collaborative XBRL creation:
The thesis assignments and 2014 implementations demonstrate this architecture works in practice for real annual reports and audit reports.
This document explains the complexity of XBRL documents as work-in-progress, the collaborative creation challenges, and architectural solutions including GLOMIDCO's proven BPM/CMIS/ESB approach.