{"id":42099137,"url":"https://github.com/cap-java/cds-feature-attachments","last_synced_at":"2026-05-21T17:01:47.529Z","repository":{"id":234131986,"uuid":"770459348","full_name":"cap-java/cds-feature-attachments","owner":"cap-java","description":"Support for attachments","archived":false,"fork":false,"pushed_at":"2026-02-05T14:24:23.000Z","size":3879,"stargazers_count":5,"open_issues_count":21,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-05T19:35:01.981Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cap-java.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-11T15:35:06.000Z","updated_at":"2026-02-05T09:21:55.000Z","dependencies_parsed_at":"2025-01-17T07:18:41.170Z","dependency_job_id":"add18737-f3b6-429f-8585-b6ef486514e3","html_url":"https://github.com/cap-java/cds-feature-attachments","commit_stats":null,"previous_names":["cap-java/cds-feature-attachments"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/cap-java/cds-feature-attachments","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-java%2Fcds-feature-attachments","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-java%2Fcds-feature-attachments/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-java%2Fcds-feature-attachments/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-java%2Fcds-feature-attachments/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cap-java","download_url":"https://codeload.github.com/cap-java/cds-feature-attachments/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-java%2Fcds-feature-attachments/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29164874,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T12:44:37.655Z","status":"ssl_error","status_checked_at":"2026-02-06T12:44:13.991Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-26T12:11:21.175Z","updated_at":"2026-04-10T10:06:23.390Z","avatar_url":"https://github.com/cap-java.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Java Build with Maven](https://github.com/cap-java/cds-feature-attachments/actions/workflows/main.yml/badge.svg)](https://github.com/cap-java/cds-feature-attachments/actions/workflows/main.yml) \n[![Deploy new Version with Maven](https://github.com/cap-java/cds-feature-attachments/actions/workflows/release.yml/badge.svg)](https://github.com/cap-java/cds-feature-attachments/actions/workflows/release.yml) \n[![REUSE status](https://api.reuse.software/badge/github.com/cap-java/cds-feature-attachments)](https://api.reuse.software/info/github.com/cap-java/cds-feature-attachments)\n\n# Attachments Plugin for SAP Cloud Application Programming Model (CAP)\n\nThe `com.sap.cds:cds-feature-attachments` dependency is\na [CAP Java plugin](https://cap.cloud.sap/docs/java/building-plugins) that provides out-of-the box attachments storage\nand handling by using an aspect Attachments.\n\nIt supports the [AWS, Azure, and Google object stores](storage-targets/cds-feature-attachments-oss) and can connect to a [malware scanner](#malware-scanner).\n\n## Table of Contents\n\n\u003c!-- TOC --\u003e\n\n* [Quick Start](#quick-start)\n* [Usage](#usage)\n  * [MVN Setup](#mvn-setup)\n  * [Changes in the CDS Models and for the UI](#changes-in-the-cds-models-and-for-the-UI)\n  * [Try the Bookshop Sample](#try-the-bookshop-sample)\n  * [Storage Targets](#storage-targets)\n  * [Malware Scanner](#malware-scanner)\n  * [Specify the maximum file size](#specify-the-maximum-file-size)\n  * [Restrict allowed MIME types](#restrict-allowed-mime-types)\n  * [Outbox](#outbox)\n  * [Restore Endpoint](#restore-endpoint)\n    * [Motivation](#motivation)\n    * [HTTP Endpoint](#http-endpoint)\n    * [Security](#security)\n* [Releases: Maven Central and Artifactory](#releases-maven-central-and-artifactory)\n* [Minimum UI5 and CAP Java Version](#minimum-ui5-and-cap-java-version)\n* [Architecture Overview](#architecture-overview)\n  * [Design](#design)\n  * [Multitenancy](#multitenancy)\n  * [Object Stores](#object-stores)\n  * [Model Texts](#model-texts)\n* [Monitoring \\\u0026 Logging](#monitoring--logging)\n* [Support, Feedback, Contributing](#support-feedback-contributing)\n* [References \\\u0026 Links](#references--links)\n\n## Quick Start\n\nFor a quick setup with in-memory storage:\n\n- Add the `cds-feature-attachments` Maven dependency to the `srv/pom.xml` and configure the `cds-maven-plugin` with the `resolve` goal as described in [MVN Setup](#mvn-setup).\n- Extend the CDS model with the `Attachments` aspect and annotate the service for UI integration as explained in [Changes in the CDS Models and for the UI](#changes-in-the-cds-models-and-for-the-UI).\n\nFor a complete working example, see the [bookshop sample](samples/bookshop/).\n\nThe [incidents app](https://github.com/cap-java/incidents-app/) provides a demonstration of how to use this plugin.\n\nFor object store integration, see [Amazon, Azure, and Google Object Stores](storage-targets/cds-feature-attachments-oss).\n\n## Usage\n\n### MVN Setup\n\nAs described in the [CAP Java Documentation](https://cap.cloud.sap/docs/java/building-plugins#reference-the-new-cds-model-in-an-existing-cap-java-project), the attachments plugin needs to be referenced in the `srv/pom.xml` of the consuming CAP Java application:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.sap.cds\u003c/groupId\u003e\n    \u003cartifactId\u003ecds-feature-attachments\u003c/artifactId\u003e\n    \u003cversion\u003e${latest-version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nAdditionally, the `cds-maven-plugin` must be configured with the `resolve` goal to ensure CDS models from dependencies are available.\nFor this, add the following to the `srv/pom.xml` before the entry `build` as well:\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003ecom.sap.cds\u003c/groupId\u003e\n    \u003cartifactId\u003ecds-maven-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e${cds.services.version}\u003c/version\u003e\n    \u003cexecutions\u003e\n        \u003cexecution\u003e\n            \u003cid\u003ecds.resolve\u003c/id\u003e\n            \u003cgoals\u003e\n                \u003cgoal\u003eresolve\u003c/goal\u003e\n            \u003c/goals\u003e\n        \u003c/execution\u003e\n    \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\nAfter that, the aspect `Attachments` can be used in the application's CDS model.\n\n### Changes in the CDS Models and for the UI\n\nTo use the aspect `Attachments` on an existing entity, the corresponding entity needs to be extended in a CDS file in the `srv` module.\nThe following example shows how to extend the entity `Incidents` in the `srv` module with an additional `attachments.cds` file, it also directly adds the respective UI Facet.\nTo use this file with the [incidents app](https://github.com/cap-java/incidents-app/), check out the source code, copy the [file from the xmpls folder](https://github.com/cap-java/incidents-app/blob/main/xmpls/attachments.cds) to the srv folder and run the app as explained in the [incidents app README](https://github.com/cap-java/incidents-app/blob/main/README.md).\n\n```cds\nusing { sap.capire.incidents as my } from '../db/schema';\nusing { sap.attachments.Attachments } from 'com.sap.cds/cds-feature-attachments';\nextend my.Incidents with {\n  attachments: Composition of many Attachments;\n}\nusing { ProcessorService as service } from '../app/services';\nannotate service.Incidents with @(\n  UI.Facets: [\n    ...,\n    {\n      $Type  : 'UI.ReferenceFacet',\n      ID     : 'AttachmentsFacet',\n      Label  : '{i18n\u003eattachments}',\n      Target : 'attachments/@UI.LineItem'\n    }\n  ]\n);\n```\n\nThe UI Facet can also be added directly after other UI Facets in a `cds` file in the `app` folder.\n\n### Try the Bookshop Sample\n\nThe easiest way to get started is with the included [bookshop sample](samples/bookshop/):\n\n```bash\ncd samples/bookshop\nmvn compile\nmvn spring-boot:run\n```\n\nThen browse to http://localhost:8080/browse/index.html to see attachments in action.\n\nFor detailed setup instructions and implementation details, see the [bookshop sample README](samples/bookshop/README.md).\n\n### Storage Targets\n\nBy default, the plugin operates without a dedicated storage target, storing attachments directly in the [underlying database](cds-feature-attachments/src/main/resources/cds/com.sap.cds/cds-feature-attachments/attachments.cds#L17).\n\nOther available storage targets:\n\n- [Amazon, Azure, and Google Object Stores](storage-targets/cds-feature-attachments-oss)\n- [local file system as a storage backend](storage-targets/cds-feature-attachments-fs)\n\n\u003e **Warning:** The [file system storage target](storage-targets/cds-feature-attachments-fs) (`cds-feature-attachments-fs`) is intended **only for local development and testing purposes**. It is **not suitable for production or deployed environments**. For production use, configure one of the supported object stores (AWS, Azure, or Google).\n\nWhen using a dedicated storage target, the attachment is not stored in the underlying database; instead, it is saved on the specified storage target and only a reference to the file is kept in the database, as defined in the [CDS model](cds-feature-attachments/src/main/resources/cds/com.sap.cds/cds-feature-attachments/attachments.cds#L20).\n\n### Malware Scanner\n\nThis plugin checks for a binding to\nthe [SAP Malware Scanning Service](https://help.sap.com/docs/malware-scanning-servce), which needs to have the label `malware-scanner`. The entry in the [mta-file](https://cap.cloud.sap/docs/guides/deployment/to-cf#add-mta-yaml) may look like:\n\n```\n_schema-version: '0.1'\nID: consuming-app\nversion: 1.0.0\ndescription: \"App consuming the attachments plugin with a malware scanner\"\nparameters:\n  ...\nmodules:\n  - name: consuming-app-srv\n# ------------------------------------------------------------\n    type: java\n    path: srv\n    parameters:\n      ...\n    properties:\n      ...\n    build-parameters:\n      ...\n    requires:\n      - name: consuming-app-hdi-container\n      - name: consuming-app-uaa\n      - name: cf-logging\n      - name: malware-scanner\n...\nresources:\n  ...\n  - name: malware-scanner\n    type: org.cloudfoundry.managed-service\n    parameters:\n      service: malware-scanner\n      service-plan: clamav\n```\n\nThe malware scanner is used in the `AttachmentService` to scan\nattachments.\n\n\u003e [!Note]\n\u003e The malware scanner supports both mTLS and basic authentication; mTLS is recommended as basic authentication has been deprecated.\n\nIf there is no malware scanner available, the attachments are automatically marked as `Clean`.\n\nScan status codes:\n\n- `Clean`: Only attachments with the status `Clean` are accessible.\n- `Scanning`: Immediately after upload, the attachment is marked as `Scanning`. Depending on processing speed, it may already appear as `Clean` when the page is reloaded.\n- `Unscanned`: Attachment is still unscanned.\n- `Failed`: Scanning failed.\n- `Infected`: The attachment is infected.\n\n### Specify the maximum file size\n\nYou can specify the maximum file size by annotating the attachments content property with @Validation.Maximum\n\n```cds\nentity Books {\n  ...\n  attachments: Composition of many Attachments;\n}\n\nannotate Books.attachments with {\n  content @Validation.Maximum : '20MB';\n}\n```\n\nThe @Validation.Maximum value is a size string consisting of a number followed by a unit. The following units are supported:\n- B (bytes)\n- KB, MB, GB, TB (decimal units)\n- KiB, MiB, GiB, TiB (binary units)\n\nThe default is 400MB\n\n### Restrict allowed MIME types\n\nYou can restrict which MIME types are allowed for attachments by annotating the content property with @Core.AcceptableMediaTypes. This validation is performed during file upload.\n\n```cds\nentity Books {\n  ...\n  attachments: Composition of many Attachments;\n}\n\nannotate Books.attachments with {\n  content @Core.AcceptableMediaTypes : ['image/jpeg', 'image/png', 'application/pdf'];\n}\n```\n\nWildcard patterns are supported:\n\n```cds\nannotate Books.attachments with {\n  content @Core.AcceptableMediaTypes : ['image/*', 'application/pdf'];\n}\n```\n\nTo allow all MIME types (default behavior), either omit the annotation or use:\n\n```cds\nannotate Books.attachments with {\n  content @Core.AcceptableMediaTypes : ['*/*'];\n}\n```\n\n\n### Outbox\n\nIn this plugin the [persistent outbox](https://cap.cloud.sap/docs/java/outbox#persistent) is used to mark attachments as\ndeleted.\nWhen using this plugin, the persistent outbox is enabled by default.\nIn the capire documentation of the [persistent outbox](https://cap.cloud.sap/docs/java/outbox#persistent) is it\ndescribed how to overwrite\nthe default outbox configuration.\n\nIf the default shall be used, nothing needs to be done.\n\n### Restore Endpoint\n\nThe attachment service has an event `RESTORE_ATTACHMENTS`.\nThis event can be called with a timestamp to restore externally stored attachments.\n\n#### Motivation\n\nDocuments which are marked as deleted can be restored.\n\nThe use cases behind this feature are:\n\n- Restoring attachments after a database backup is restored:\n  When restoring a database backup, any attachments stored in external storage (object stores, etc.) also need to be restored to maintain data consistency.\n- Restoring attachments that were marked as deleted:\n  The restore endpoint provides a way to recover attachments that were previously marked as deleted, making it possible to undo deletions if needed.\n\nIn the default implementation of the technical service `AttachmentService` this is not needed as the attachments are\nstored directly in the database and are restored with the database.\n\nIf the default implementation is replaced by overwriting the [respective handler](cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/service/handler/DefaultAttachmentsServiceHandler.java#L87), for example by the\n[SAP Document Management Service](https://help.sap.com/docs/document-management-service), then the overwriting plugin\nneeds to handle the restore of attachments.\n\nIn such cases the restore endpoint can be used to restore attachments.\n\nHow long attachments are marked as deleted before they are actually deleted depends on the configuration of the used storage.\n\n#### HTTP Endpoint\n\nThere is no predefined endpoint for the restore action.\nTo call the action of the service from outside the application a service could be defined as in the following example:\n\n```cds\nservice RestoreAttachments {\n  action restoreAttachments (restoreTimestamp: Timestamp);\n}\n```\n\nSee [Security](#security) for how to secure this endpoint.\nThe action `restoreAttachments` could get in a timestamp from which the attachments need to be restored.\nThe action could be called with a POST request to the endpoint:\n\n- OData v4: `/odata/v4/RestoreAttachments/restoreAttachments`\n- OData v2: `/odata/v2/RestoreAttachments/restoreAttachments`\n\nWith the body:\n\n```json\n{\n  \"restoreTimestamp\": \"2024-04-17T10:36:38.813491100Z\"\n}\n```\n\nThe action needs to be implemented and can call the attachment service as in the following example:\n\n```java\n\n@ServiceName(RestoreAttachments_.CDS_NAME)\npublic class RestoreAttachmentsHandler implements EventHandler {\n\n\tprivate final AttachmentService attachmentService;\n\n\tpublic RestoreAttachmentsHandler(AttachmentService attachmentService) {\n\t\tthis.attachmentService = attachmentService;\n\t}\n\n\t@On(event = RestoreAttachmentsContext.CDS_NAME)\n\tpublic void restoreAttachments(RestoreAttachmentsContext context) {\n\t\tattachmentService.restoreAttachment(context.getRestoreTimestamp());\n\t\tcontext.setCompleted();\n\t}\n\n}\n```\n\nIn the Spring Boot context the `AttachmentService` can be autowired in the handler.\n\n#### Security\n\nTo secure the endpoint, security annotations can be used. For example:\n\n```cds\nusing {sap.attachments.Attachments} from `com.sap.cds/cds-feature-attachments`;\n\nentity Items : cuid {\n    ...\n    attachments : Composition of many Attachments;\n    ...\n}\n\nannotate RestoreAttachments with @(requires: 'internal-user');\n```\n\nHere the `RestoreAttachments` service is annotated with the `requires` annotation to secure the service.\nVarious other annotations can be used to secure the service.\n\nMore information about the CAP Java security concept can be found in\nthe [CAP Java Documentation](https://cap.cloud.sap/docs/java/security).\n\n## Releases: Maven Central and Artifactory\n\n- The plugin is released to Maven Central at: https://central.sonatype.com/artifact/com.sap.cds/cds-feature-attachments (public access).\n- See the [changelog](./doc/CHANGELOG.md) for the latest changes.\n\n- To test snapshot versions of this plugin, the artifactory in `${HOME}/.m2/settings.xml` needs to be configured. See [the maven settings](https://maven.apache.org/settings.html#Repositories) for further details.\n\n## Minimum UI5 and CAP Java Version\n\n| Component | Minimum Version |\n| --------- | --------------- |\n| CAP Java  | 3.10.3          |\n| UI5       | 1.136.0         |\n\n## Architecture Overview\n\n### Design\n\n- [Design Details](./doc/Design.md)\n- [Process of Creating, Reading and Deleting an Attachment](./doc/Processes.md)\n\n### Multitenancy\n\n- When using SAP HANA as the storage target, multitenancy support depends on the consuming application. In most cases, multitenancy is achieved by using a dedicated schema for each tenant, providing strong data isolation at the database level.\n- When using an [object store](storage-targets/cds-feature-attachments-oss) as the storage target, shared-bucket multitenancy is supported (since version 1.5.0). The plugin prefixes object keys with the tenant ID to ensure tenant isolation, and automatically cleans up tenant data on unsubscribe. See [Object Stores Multitenancy](storage-targets/cds-feature-attachments-oss#multitenancy) for configuration details.\n\n### Object Stores\n\nSee [Object Stores](storage-targets/cds-feature-attachments-oss).\n\n### Model Texts\n\nIn the model, several fields are annotated with the `@title` annotation. Default texts are provided in [35 languages](https://github.com/cap-java/cds-feature-attachments/tree/main/cds-feature-attachments/src/main/resources/cds/com.sap.cds/cds-feature-attachments/_i18n). If these defaults are not sufficient for an application, they can be overwritten by applications with custom texts or translations.\n\nThe following table gives an overview of the fields and the i18n codes:\n\n| Field Name | i18n Code             |\n| ---------- | --------------------- |\n| `content`  | `attachment_content`  |\n| `mimeType` | `attachment_mimeType` |\n| `fileName` | `attachment_fileName` |\n| `status`   | `attachment_status`   |\n| `note`     | `attachment_note`     |\n\nIn addition to the field names, header information (`@UI.HeaderInfo`) are also annotated:\n\n| Header Info      | i18n Code     |\n| ---------------- | ------------- |\n| `TypeName`       | `attachment`  |\n| `TypeNamePlural` | `attachments` |\n\n## Monitoring \u0026 Logging\n\nTo configure logging for the attachments plugin, add the following line to the `/srv/src/main/resources/application.yaml` of the consuming application:\n\n```\nlogging:\n  level:\n    ...\n    '[com.sap.cds.feature.attachments]': DEBUG\n...\n```\n\n## Support, Feedback, Contributing\n\nThis project is open to feature requests/suggestions, bug reports etc.\nvia [GitHub issues](https://github.com/cap-java/cds-feature-attachments/issues).\n\nContribution and feedback are encouraged and always welcome. For more information about how to contribute, the project\nstructure, as well as additional contribution information,\nsee our [Contribution Guidelines](./doc/CONTRIBUTING.md).\n\n## References \u0026 Links\n\n- [License](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcap-java%2Fcds-feature-attachments","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcap-java%2Fcds-feature-attachments","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcap-java%2Fcds-feature-attachments/lists"}