Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions cds-feature-sap-document-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,39 @@ Submit a document via your application. The plugin logs progress at `INFO` level

---

## Usage
## Multi-Tenancy

> **Note:** In the current version, document extraction can only be triggered programmatically via event emission, as shown in the [Integration Guide](#integration-guide). Annotation-based triggering (e.g. declaratively marking an entity field or action to trigger extraction) is not yet supported and is planned for a future release.
The plugin supports multi-tenancy for SAP BTP SaaS applications. When multi-tenancy is detected at startup, each subscriber tenant's documents are fully isolated within the shared Document AI service instance.

## Multi-Tenancy
### How It Works

Multi-tenancy is detected automatically at startup — no configuration flag is needed. The plugin checks for either:
- A CAP MTX sidecar URL (`cds.multitenancy.sidecar.url`)
- The presence of a `DeploymentService` in the CDS service catalog

When detected:
- **Data isolation** — every Document AI API call includes a `clientId` query parameter set to the tenant ID (`?clientId=<tenantId>` on submit, `&clientId=<tenantId>` on poll). The Document AI service uses this to isolate each tenant's documents, schemas, and jobs within the shared service instance. Authentication uses the provider's service binding credentials.
- **Per-tenant polling** — the polling handler groups active jobs by tenant and switches the CDS request context per group, ensuring database operations are correctly scoped to each tenant's schema.
- **Tenant lifecycle** — on tenant unsubscribe, all active jobs (`PENDING`, `SUBMITTED`, `RUNNING`) belonging to that tenant are automatically marked `FAILED` so they do not generate poll errors after the tenant is removed.

### MTX Sidecar Configuration

If your app uses a CAP MTX sidecar, configure its URL in `application.yaml`:

```yaml
cds:
multitenancy:
sidecar:
url: <<side-car-url>>
```

Multi-tenancy is not implemented in the current version and is planned for a future release. The `tenantId` field is stored on the `ExtractionJob` entity as groundwork.
If you use an embedded MTX setup (no sidecar URL), multi-tenancy is detected automatically via the presence of `DeploymentService` in the CDS service catalog — no additional configuration is needed.

---
Comment thread
samyuktaprabhu marked this conversation as resolved.

## Usage

> **Note:** In the current version, document extraction can only be triggered programmatically via event emission, as shown in the [Integration Guide](#integration-guide). Annotation-based triggering (e.g. declaratively marking an entity field or action to trigger extraction) is not yet supported and is planned for a future release.

### CDS Model

Expand Down Expand Up @@ -389,7 +415,6 @@ The plugin communicates with the SAP Document Information Extraction service via

## Known Limitations

- **Multi-tenancy** — not implemented; all jobs run in a single-tenant context. Planned for a future release.
- **Annotation-based triggering** — document extraction can only be initiated programmatically via event emission; declarative triggering is not yet supported.

---
Expand Down
16 changes: 10 additions & 6 deletions cds-feature-sap-document-ai/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,24 @@ The `ExtractionJob` entity uses `cuid` (auto-generated UUID primary key) and `ma

At startup it:

- Detects multi-tenancy by checking for a CAP MTX sidecar URL (`cds.multitenancy.sidecar.url`) or the presence of `DeploymentService` in the service catalog.
- Registers `ExtractionServiceImpl` as a named CDS service in the service catalog.
- Resolves the Document AI service binding from the environment by the label `sap-document-information-extraction`.
- Constructs an OAuth2-authenticated HTTP destination via the SAP Cloud SDK if a binding is found.
- Wires all resolved dependencies into `ExtractionServiceImpl`.
- Registers `DocumentSubmissionHandler` unconditionally.
- Registers `ExtractionPollingHandler` only when a valid Document AI client was successfully built.
- Registers `DocumentAiSetupHandler` only when multi-tenancy is enabled.

If no binding is found or the destination cannot be initialised, the plugin starts in degraded mode - events are accepted and jobs are queued as `PENDING`, but no extraction processing occurs.

### Handlers

| Handler | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DocumentSubmissionHandler` | Listens for `DocumentExtraction` events on any `ApplicationService`. Service-name-agnostic by design - consumers emit events from their own service without coupling to the plugin's internal service name. Delegates to `ExtractionService` and completes the event context. |
| `ExtractionPollingHandler` | Registered against the persistent unordered outbox. Polls the Document AI service for all active jobs on each invocation. Self-reschedules after the configured interval if jobs remain active. Stops automatically when all jobs reach a terminal status. |
| `DocumentSubmissionHandler` | Listens for `DocumentExtraction` events on any `ApplicationService`. Service-name-agnostic by design - consumers emit events from their own service without coupling to the plugin's internal service name. Delegates to `ExtractionService` and completes the event context. Emits a `DocumentExtractionResult` event immediately if submission fails. |
| `ExtractionPollingHandler` | Registered against the persistent unordered outbox. In multi-tenant mode, groups active jobs by tenant and switches the CDS request context per group so each job uses the correct subscriber OAuth token. Self-reschedules after the configured interval if jobs remain active. Stops automatically when all jobs reach a terminal status. |
| `DocumentAiSetupHandler` | Registered only when multi-tenancy is enabled. Hooks into the CAP MTX `DeploymentService` lifecycle. On subscribe: logs tenant onboarding. On unsubscribe: marks all active jobs for that tenant as `FAILED` to prevent poll errors after credentials are revoked. |

### Services

Expand Down Expand Up @@ -204,11 +207,12 @@ Unit tests are located in `sap-document-ai/src/test/java`. Each production class

| Test Class | What is tested |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| `DocumentSubmissionHandlerTest` | Event handler delegation, PENDING and FAILED logging |
| `DocumentSubmissionHandlerTest` | Event handler delegation, PENDING and FAILED logging, result event emission on submission failure |
| `ExtractionServiceImplTest` | Job creation, submission flow, concurrent update handling, failure marking, outbox scheduling |
| `ExtractionPollingHandlerTest` | Poll cycle logic, Document AI status mapping, result emission, self-rescheduling, per-job error isolation |
| `DefaultDocumentAiClientTest` | HTTP submit and poll calls, response parsing, error wrapping for all three exception types |
| `DocumentAiServiceConfigurationTest` | Startup wiring, binding resolution, conditional handler registration |
| `ExtractionPollingHandlerTest` | Poll cycle logic, Document AI status mapping, result emission, self-rescheduling, per-job error isolation, per-tenant context switching in multi-tenant mode |
| `DocumentAiSetupHandlerTest` | Subscribe logging, unsubscribe job marking, zero-job unsubscribe |
| `DefaultDocumentAiClientTest` | HTTP submit and poll calls, `clientId` query param appended per tenant, response parsing, error wrapping |
| `DocumentAiServiceConfigurationTest` | Startup wiring, binding resolution, multi-tenancy detection, conditional handler registration |
| `StatusTransitionValidatorTest` | All valid and invalid transitions |
| `ExceptionsTest` | Exception message and cause propagation |

Expand Down
Loading
Loading