|
5 | 5 | [](https://openjdk.org) |
6 | 6 | [](https://spring.io/projects/spring-boot) |
7 | 7 |
|
8 | | -> ECM core library providing document management, e-signature, intelligent document processing, and folder security through a port/adapter architecture. |
| 8 | +> Reactive Enterprise Content Management abstraction for Spring Boot — provider-agnostic ports for document storage, e-signature, intelligent document processing, folders, security and audit, with pluggable adapters selected by configuration. |
9 | 9 |
|
10 | 10 | --- |
11 | 11 |
|
|
17 | 17 | - [Installation](#installation) |
18 | 18 | - [Quick Start](#quick-start) |
19 | 19 | - [Configuration](#configuration) |
| 20 | +- [Architecture](#architecture) |
| 21 | +- [Observability](#observability) |
20 | 22 | - [Documentation](#documentation) |
21 | 23 | - [Contributing](#contributing) |
22 | 24 | - [License](#license) |
23 | 25 |
|
24 | 26 | ## Overview |
25 | 27 |
|
26 | | -Firefly Framework ECM provides Enterprise Content Management capabilities through a hexagonal (port/adapter) architecture. It defines ports for document management, e-signature workflows, intelligent document processing (IDP), folder management, audit trails, and document security, which are implemented by provider-specific adapter modules. |
| 28 | +Firefly Framework ECM provides Enterprise Content Management capabilities to Spring Boot applications through a **hexagonal (port/adapter) architecture**. Your application code depends only on a stable set of reactive **port interfaces** — it never talks to a vendor SDK directly. Concrete behaviour is supplied by **adapters** that are discovered on the classpath and selected by configuration, so you can switch from a cloud provider to an on-premise system (or to a no-op test double) without touching business logic. |
27 | 29 |
|
28 | | -The core module includes the adapter registry and selection mechanism, enabling runtime adapter discovery and multi-provider support. It provides domain models for documents, signature envelopes, folders, permissions, and audit events, along with comprehensive enumerations for document statuses, signature states, and processing workflows. |
| 30 | +The library is fully **reactive** (Spring WebFlux + Project Reactor): every port returns `Mono`/`Flux`, including streaming binary content via `DataBuffer`. It groups its contracts into six functional families — **document management**, **e-signature**, **intelligent document processing (IDP)**, **folder management**, **document security**, and **audit** — each guarded by an independent feature flag so you only enable (and pay the startup cost of) what you use. |
29 | 31 |
|
30 | | -Storage adapters (AWS S3, Azure Blob) and e-signature adapters (Adobe Sign, DocuSign, Logalty) are published as separate standalone modules that plug into the ECM core. |
| 32 | +Adapter discovery and routing are handled by the built-in **adapter registry/selector** (`AdapterRegistry`, `AdapterSelector`) together with the `@EcmAdapter` annotation SPI. When a feature is enabled but no real adapter is present, the auto-configuration installs a **no-op fallback** (`NoOpAdapterFactory`) so the application still starts — and logs a loud warning for security-sensitive ports (permissions and document security default to *deny*). The module ships two ready-to-use built-in adapters for development and testing: an in-memory `LocalDocumentSearchAdapter` and `LocalPermissionAdapter`. |
| 33 | + |
| 34 | +This is the **ECM core** library. Provider integrations — AWS S3 and Azure Blob (storage), DocuSign and Adobe Sign (e-signature), and IDP backends such as AWS Textract, Azure Form Recognizer and Google Document AI — plug in as adapters and are selected via `firefly.ecm.adapter-type` (storage/core) and `firefly.ecm.esignature.provider` (e-signature). The client SDK versions for those providers are managed in this module's `dependencyManagement` so adapter modules stay version-aligned. It sits alongside sibling Firefly capability cores such as `fireflyframework-idp`, `fireflyframework-notifications` and the cache/EDA cores, and builds on `fireflyframework-kernel` (foundational types) and `fireflyframework-observability` (metrics, tracing, health). |
31 | 35 |
|
32 | 36 | ## Features |
33 | 37 |
|
34 | | -- Hexagonal architecture with port/adapter pattern |
35 | | -- Document management ports: content, metadata, versioning, search |
36 | | -- E-signature ports: envelope management, signature requests, validation, proof |
37 | | -- Intelligent document processing ports: classification, extraction, validation |
38 | | -- Folder management with hierarchical structure and permissions |
39 | | -- Audit trail with event type and severity tracking |
40 | | -- Adapter registry with profile-based selection |
41 | | -- NoOp adapters for testing and development |
42 | | -- Local document search and permission adapters |
43 | | -- Resilience configuration for adapter operations |
44 | | -- Auto-configuration via `EcmAutoConfiguration` |
45 | | -- Configurable via `EcmProperties` |
| 38 | +- **Hexagonal port/adapter design** — application code depends on reactive ports; vendors plug in behind them. |
| 39 | +- **18 reactive port interfaces across 6 families:** |
| 40 | + - *Document* — `DocumentPort` (CRUD/metadata), `DocumentContentPort` (binary store/stream), `DocumentVersionPort` (versioning), `DocumentSearchPort` (search). |
| 41 | + - *E-signature* — `SignatureEnvelopePort`, `SignatureRequestPort`, `SignatureValidationPort`, `SignatureProofPort`. |
| 42 | + - *IDP* — `DocumentExtractionPort` (OCR/text), `DocumentClassificationPort`, `DocumentValidationPort`, `DataExtractionPort` (structured/forms/tables). |
| 43 | + - *Folder* — `FolderPort`, `FolderHierarchyPort`. |
| 44 | + - *Security* — `PermissionPort`, `DocumentSecurityPort`. |
| 45 | + - *Audit* — `AuditPort`. |
| 46 | +- **Annotation-driven adapter SPI** — declare a provider with `@EcmAdapter(type=…, supportedFeatures={…})`; the `AdapterRegistry` auto-discovers it and `AdapterSelector` routes by type/interface with fallback. |
| 47 | +- **Capability model** — the `AdapterFeature` enum (40+ values: `DOCUMENT_CRUD`, `CONTENT_STORAGE`, `VERSIONING`, `ESIGNATURE_ENVELOPES`, `OCR`, `TABLE_EXTRACTION`, `COMPLIANCE`, `LEGAL_HOLD`, …) plus `AdapterProfile` (`BASIC`/`STANDARD`/`ADVANCED`) describe what each adapter supports. |
| 48 | +- **Safe no-op fallbacks** — `NoOpAdapterFactory` keeps the app booting when an enabled feature has no real adapter; permission and security ports *deny by default* and warn. |
| 49 | +- **Built-in local adapters** — in-memory `LocalDocumentSearchAdapter` and `LocalPermissionAdapter` for dev/test (opt-in via properties). |
| 50 | +- **Fine-grained feature flags** — independently toggle document management, content storage, versioning, folders, hierarchy, permissions, security, search, auditing, e-signature and IDP. |
| 51 | +- **Streaming-first content** — upload/download via `byte[]` or backpressure-aware `Flux<DataBuffer>` for large files. |
| 52 | +- **Resilience built in** — Resilience4j circuit breaker, retry and time limiter wired for adapter calls (`ResilienceConfiguration`), plus connection timeout/pool/retry settings. |
| 53 | +- **Validation guardrails** — global max file size, allowed/blocked extension lists, and checksum algorithm enforced at the configuration level. |
| 54 | +- **First-class observability** — `EcmMetrics` publishes Micrometer counters, timers and distribution summaries (see [Observability](#observability)). |
| 55 | +- **Zero-config auto-configuration** — `EcmAutoConfiguration` registers everything; enabled by default via `firefly.ecm.enabled`. |
46 | 56 |
|
47 | 57 | ## Requirements |
48 | 58 |
|
49 | | -- Java 21+ |
| 59 | +- Java 21+ (Java 25 recommended) |
50 | 60 | - Spring Boot 3.x |
51 | 61 | - Maven 3.9+ |
| 62 | +- A provider adapter on the classpath for production use (e.g. AWS S3 / Azure Blob for storage, DocuSign / Adobe Sign for e-signature). Without one, enabled features fall back to no-op behaviour. |
52 | 63 |
|
53 | 64 | ## Installation |
54 | 65 |
|
| 66 | +Add the dependency. The version is managed by the Firefly BOM/parent, so you normally omit `<version>`: |
| 67 | + |
55 | 68 | ```xml |
56 | 69 | <dependency> |
57 | 70 | <groupId>org.fireflyframework</groupId> |
58 | 71 | <artifactId>fireflyframework-ecm</artifactId> |
59 | | - <version>26.02.07</version> |
| 72 | + <!-- version managed by the Firefly BOM / fireflyframework-parent --> |
60 | 73 | </dependency> |
61 | 74 | ``` |
62 | 75 |
|
| 76 | +If your project does not inherit the Firefly parent, import the BOM in `dependencyManagement` (or pin the version explicitly): |
| 77 | + |
| 78 | +```xml |
| 79 | +<dependencyManagement> |
| 80 | + <dependencies> |
| 81 | + <dependency> |
| 82 | + <groupId>org.fireflyframework</groupId> |
| 83 | + <artifactId>fireflyframework-bom</artifactId> |
| 84 | + <version>${firefly.version}</version> |
| 85 | + <type>pom</type> |
| 86 | + <scope>import</scope> |
| 87 | + </dependency> |
| 88 | + </dependencies> |
| 89 | +</dependencyManagement> |
| 90 | +``` |
| 91 | + |
| 92 | +Then add the matching provider adapter module(s) for your storage / e-signature backend. |
| 93 | + |
63 | 94 | ## Quick Start |
64 | 95 |
|
| 96 | +1. Add the dependency (above) and a provider adapter. Select it via configuration: |
| 97 | + |
| 98 | +```yaml |
| 99 | +firefly: |
| 100 | + ecm: |
| 101 | + enabled: true |
| 102 | + adapter-type: s3 # selects the storage/core adapter (e.g. AWS S3) |
| 103 | + properties: # adapter-specific settings (free-form map) |
| 104 | + bucket-name: my-documents |
| 105 | + region: us-east-1 |
| 106 | + features: |
| 107 | + document-management: true |
| 108 | + content-storage: true |
| 109 | + esignature: true # off by default — opt in |
| 110 | + esignature: |
| 111 | + provider: docusign # selects the e-signature adapter independently |
| 112 | +``` |
| 113 | +
|
| 114 | +2. Inject the reactive ports you need — your code is provider-agnostic: |
| 115 | +
|
65 | 116 | ```java |
66 | 117 | import org.fireflyframework.ecm.port.document.DocumentContentPort; |
67 | 118 | import org.fireflyframework.ecm.port.esignature.SignatureEnvelopePort; |
| 119 | +import org.springframework.stereotype.Service; |
| 120 | +import reactor.core.publisher.Mono; |
| 121 | + |
| 122 | +import java.util.UUID; |
68 | 123 |
|
69 | 124 | @Service |
70 | 125 | public class DocumentService { |
71 | 126 |
|
72 | | - private final DocumentContentPort documentPort; |
73 | | - private final SignatureEnvelopePort signaturePort; |
| 127 | + private final DocumentContentPort content; |
| 128 | + private final SignatureEnvelopePort envelopes; |
74 | 129 |
|
75 | | - public Mono<Document> uploadAndSign(byte[] content, SignatureRequest sigRequest) { |
76 | | - return documentPort.store(content) |
77 | | - .flatMap(doc -> signaturePort.createEnvelope(doc, sigRequest)); |
| 130 | + public DocumentService(DocumentContentPort content, SignatureEnvelopePort envelopes) { |
| 131 | + this.content = content; |
| 132 | + this.envelopes = envelopes; |
78 | 133 | } |
| 134 | + |
| 135 | + /** Store binary content for a document and return its storage path. */ |
| 136 | + public Mono<String> upload(UUID documentId, byte[] bytes, String mimeType) { |
| 137 | + return content.storeContent(documentId, bytes, mimeType); |
| 138 | + } |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +3. (Optional) Use the built-in in-memory adapters for local development/tests: |
| 143 | + |
| 144 | +```yaml |
| 145 | +firefly: |
| 146 | + ecm: |
| 147 | + search: |
| 148 | + enabled: true # registers LocalDocumentSearchAdapter |
| 149 | + permissions: |
| 150 | + enabled: true # registers LocalPermissionAdapter |
| 151 | +``` |
| 152 | +
|
| 153 | +To write your own adapter, annotate a port implementation with `@EcmAdapter` and the registry will discover it: |
| 154 | + |
| 155 | +```java |
| 156 | +import org.fireflyframework.ecm.adapter.EcmAdapter; |
| 157 | +import org.fireflyframework.ecm.adapter.AdapterFeature; |
| 158 | +import org.fireflyframework.ecm.port.document.DocumentContentPort; |
| 159 | +
|
| 160 | +@EcmAdapter( |
| 161 | + type = "s3", |
| 162 | + description = "AWS S3 content storage adapter", |
| 163 | + supportedFeatures = { AdapterFeature.CONTENT_STORAGE, AdapterFeature.STREAMING, AdapterFeature.CLOUD_STORAGE } |
| 164 | +) |
| 165 | +public class S3DocumentContentAdapter implements DocumentContentPort { |
| 166 | + // ... reactive implementation ... |
79 | 167 | } |
80 | 168 | ``` |
81 | 169 |
|
82 | 170 | ## Configuration |
83 | 171 |
|
| 172 | +All properties are bound under the `firefly.ecm` prefix (`EcmProperties`). The block below shows the real keys and their defaults: |
| 173 | + |
84 | 174 | ```yaml |
85 | 175 | firefly: |
86 | 176 | ecm: |
87 | | - storage: |
88 | | - provider: aws-s3 # aws-s3, azure-blob |
| 177 | + enabled: true # master switch for the ECM auto-configuration |
| 178 | + adapter-type: # storage/core adapter to select (e.g. "s3"); none by default |
| 179 | + properties: # free-form, adapter-specific settings (Map<String,Object>) |
| 180 | + # bucket-name: my-documents |
| 181 | + # region: us-east-1 |
| 182 | +
|
| 183 | + connection: |
| 184 | + connect-timeout: PT30S # connection establishment timeout |
| 185 | + read-timeout: PT5M # read/transfer timeout |
| 186 | + max-connections: 100 # max pooled connections |
| 187 | + retry-attempts: 3 # retries for transient failures |
| 188 | +
|
| 189 | + features: # independent capability toggles |
| 190 | + document-management: true |
| 191 | + content-storage: true |
| 192 | + versioning: true |
| 193 | + folder-management: true |
| 194 | + folder-hierarchy: true |
| 195 | + permissions: true |
| 196 | + security: true |
| 197 | + search: true |
| 198 | + auditing: true |
| 199 | + esignature: false # opt-in |
| 200 | + virus-scanning: false # opt-in |
| 201 | + content-extraction: false # opt-in |
| 202 | + idp: false # opt-in (Intelligent Document Processing) |
| 203 | +
|
| 204 | + defaults: |
| 205 | + max-file-size-mb: 100 |
| 206 | + allowed-extensions: [pdf, doc, docx, txt, jpg, png] |
| 207 | + blocked-extensions: [exe, bat, cmd, scr] |
| 208 | + checksum-algorithm: SHA-256 |
| 209 | + default-folder: "/" |
| 210 | +
|
| 211 | + performance: |
| 212 | + batch-size: 100 |
| 213 | + cache-enabled: true |
| 214 | + cache-expiration: PT30M |
| 215 | + compression-enabled: true |
| 216 | +
|
89 | 217 | esignature: |
90 | | - provider: docusign # adobe-sign, docusign, logalty |
| 218 | + provider: # e-signature adapter (e.g. "docusign", "adobe-sign") |
| 219 | +
|
| 220 | + # The two built-in local adapters are opt-in and live outside the blocks above: |
| 221 | + search: |
| 222 | + enabled: false # registers LocalDocumentSearchAdapter when true |
| 223 | + permissions: |
| 224 | + enabled: false # registers LocalPermissionAdapter when true |
91 | 225 | ``` |
92 | 226 |
|
93 | | -## Documentation |
| 227 | +Key properties: |
| 228 | + |
| 229 | +| Property | Default | Purpose | |
| 230 | +| --- | --- | --- | |
| 231 | +| `firefly.ecm.enabled` | `true` | Master switch. When `false`, no ECM beans are created. | |
| 232 | +| `firefly.ecm.adapter-type` | *(none)* | Selects the storage/core adapter by its `@EcmAdapter(type=…)`. | |
| 233 | +| `firefly.ecm.properties` | *(empty)* | Adapter-specific key/value settings (bucket, region, credentials, …). | |
| 234 | +| `firefly.ecm.esignature.provider` | *(none)* | Selects the e-signature adapter independently of `adapter-type`. | |
| 235 | +| `firefly.ecm.features.*` | see above | Enable/disable each capability family. `esignature` and `idp` are **off** by default; most others **on**. | |
| 236 | +| `firefly.ecm.defaults.*` | see above | Upload validation: size limit, allowed/blocked extensions, checksum algorithm, default folder. | |
| 237 | +| `firefly.ecm.connection.*` | see above | Timeouts, pool size and retry attempts for adapter connections. | |
| 238 | +| `firefly.ecm.performance.*` | see above | Batch size, caching and compression toggles. | |
| 239 | +| `firefly.ecm.search.enabled` | `false` | Registers the in-memory `LocalDocumentSearchAdapter`. | |
| 240 | +| `firefly.ecm.permissions.enabled` | `false` | Registers the in-memory `LocalPermissionAdapter`. | |
| 241 | + |
| 242 | +> Security note: if `permissions` or `security` is enabled but no real adapter is found, the no-op fallback **denies by default** and logs a warning. Always configure a real adapter for production. |
| 243 | + |
| 244 | +## Architecture |
| 245 | + |
| 246 | +``` |
| 247 | +your application |
| 248 | + │ depends only on ports (reactive interfaces) |
| 249 | + ▼ |
| 250 | +┌─────────────────────────────────────────────────────────────┐ |
| 251 | +│ ECM core (this module) │ |
| 252 | +│ │ |
| 253 | +│ Ports: document · esignature · idp · folder · security · │ |
| 254 | +│ audit (Mono / Flux) │ |
| 255 | +│ │ |
| 256 | +│ Routing: @EcmAdapter → AdapterRegistry → AdapterSelector │ |
| 257 | +│ (by adapter-type / esignature.provider) │ |
| 258 | +│ │ |
| 259 | +│ Fallback: NoOpAdapterFactory (deny-by-default for security) │ |
| 260 | +│ Built-in: LocalDocumentSearchAdapter, LocalPermissionAdapter│ |
| 261 | +└─────────────────────────────────────────────────────────────┘ |
| 262 | + ▲ ▲ |
| 263 | + │ classpath adapters │ |
| 264 | + storage adapters e-signature / IDP adapters |
| 265 | + (S3, Azure Blob, …) (DocuSign, Adobe Sign, Textract, …) |
| 266 | +``` |
| 267 | +
|
| 268 | +`EcmAutoConfiguration` registers the registry, selector, no-op factory and `EcmPortProvider`, then exposes one bean per port — each gated by its `firefly.ecm.features.*` flag and resolved through the selector with a no-op fallback. |
| 269 | +
|
| 270 | +## Observability |
94 | 271 |
|
95 | | -Additional documentation is available in the [docs/](docs/) directory: |
| 272 | +`EcmMetrics` (auto-configured via `EcmObservabilityAutoConfiguration`, built on `fireflyframework-observability`) publishes Micrometer meters: |
| 273 | +
|
| 274 | +- `firefly.ecm.documents.operations` — counter, tagged by `operation` |
| 275 | +- `firefly.ecm.operation.duration` — timer, tagged by `operation`, `provider` |
| 276 | +- `firefly.ecm.bytes.transferred` — distribution summary of payload bytes (by `direction`, `provider`) |
| 277 | +- `firefly.ecm.errors` — failed operations, tagged by `operation`, `provider` |
| 278 | +- `firefly.ecm.signatures.completed` — successful e-signature workflows, tagged by `provider` |
| 279 | +
|
| 280 | +## Documentation |
96 | 281 |
|
97 | | -- [Architecture](docs/architecture.md) |
98 | | -- [Configuration](docs/configuration.md) |
99 | | -- [Configuration Reference](docs/configuration-reference.md) |
100 | | -- [Testing](docs/testing.md) |
| 282 | +- Framework module catalog and docs hub: [fireflyframework on GitHub](https://github.com/fireflyframework) |
| 283 | +- In-repo docs ([`docs/`](docs/)): |
| 284 | + - [Architecture](docs/architecture.md) |
| 285 | + - [Configuration](docs/configuration.md) · [Configuration Reference](docs/configuration-reference.md) |
| 286 | + - [Testing](docs/testing.md) |
| 287 | + - Adapter integration guides ([`docs/adapters/`](docs/adapters)) — S3, DocuSign, Adobe Sign |
| 288 | + - IDP integration guides ([`docs/idp/`](docs/idp)) — AWS Textract, Azure Form Recognizer, Google Document AI |
| 289 | + - Usage examples ([`docs/examples/`](docs/examples)) — basic usage, document versioning, folder management |
101 | 290 |
|
102 | 291 | ## Contributing |
103 | 292 |
|
|
0 commit comments