|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +CAP Java plugin providing out-of-the-box attachment storage and handling via the `Attachments` CDS aspect. |
| 4 | + |
| 5 | +## Principles |
| 6 | + |
| 7 | +- **Think before coding.** Read the relevant source files before proposing changes. Understand the handler chain, event flow, and CDS model before touching anything. |
| 8 | +- **Simplicity first.** Follow existing patterns exactly. No new abstractions, helpers, or "improvements" beyond the task. |
| 9 | +- **Surgical changes.** Change only what is needed. Don't refactor neighbors, add comments to untouched code, or introduce feature flags. |
| 10 | +- **Goal-driven execution.** Every edit must serve the stated task. If unsure, ask. |
| 11 | + |
| 12 | +## Project Layout |
| 13 | + |
| 14 | +``` |
| 15 | +cds-feature-attachments/ # Core plugin (handlers, services, CDS model) |
| 16 | +storage-targets/ |
| 17 | + cds-feature-attachments-fs/ # File system storage (dev only) |
| 18 | + cds-feature-attachments-oss/ # Object store (AWS S3, Azure, GCS) |
| 19 | +integration-tests/ # Spring Boot integration tests |
| 20 | + generic/ # Default storage tests |
| 21 | + mtx-local/ # Multi-tenancy tests |
| 22 | + oss/ # Object store tests |
| 23 | +samples/bookshop/ # Sample CAP Java app |
| 24 | +``` |
| 25 | + |
| 26 | +Root package: `com.sap.cds.feature.attachments` |
| 27 | + |
| 28 | +## Build & Test (Maven) |
| 29 | + |
| 30 | +Java 17+ and Maven 3.6.3+ required. |
| 31 | + |
| 32 | +```bash |
| 33 | +mvn clean install # Full build with tests |
| 34 | +mvn clean install -DskipTests # Build only |
| 35 | +mvn test # Unit tests |
| 36 | +mvn verify # Unit + integration tests |
| 37 | +mvn test -Dtest=FooTest # Single test class |
| 38 | +mvn test -Dtest=FooTest#barMethod # Single test method |
| 39 | +mvn spotless:apply # Fix formatting |
| 40 | +mvn verify -Platest-test-version # Test against latest CAP Java |
| 41 | +``` |
| 42 | + |
| 43 | +**Note:** `mvn clean compile` or `mvn clean install` can occasionally fail due to a file lock. If this happens, run `mvn clean` and `mvn compile`/`mvn install` as separate commands, or just drop the `clean`. |
| 44 | + |
| 45 | +## Code Style |
| 46 | + |
| 47 | +- **Formatter:** Google Java Format via Spotless. Run `mvn spotless:apply` before committing. |
| 48 | +- **License header** required on every Java file: |
| 49 | + ```java |
| 50 | + /* |
| 51 | + * © YEAR SAP SE or an SAP affiliate company and cds-feature-attachments contributors. |
| 52 | + */ |
| 53 | + ``` |
| 54 | + ``` |
| 55 | +- **Imports:** static first, then non-static, both alphabetical (handled by Spotless). |
| 56 | +
|
| 57 | +## Architecture |
| 58 | +
|
| 59 | +### Handler Layer (`handler/`) |
| 60 | +
|
| 61 | +Handlers are CAP event handlers registered for all services of a given type. |
| 62 | +
|
| 63 | +**ApplicationService handlers** (CRUD on attachment entities): |
| 64 | +- `CreateAttachmentsHandler` / `UpdateAttachmentsHandler` / `DeleteAttachmentsHandler` / `ReadAttachmentsHandler` |
| 65 | +
|
| 66 | +**DraftService handlers** (draft lifecycle): |
| 67 | +- `DraftActiveAttachmentsHandler` / `DraftPatchAttachmentsHandler` / `DraftCancelAttachmentsHandler` |
| 68 | +
|
| 69 | +Handler registration pattern: |
| 70 | +```java |
| 71 | +@ServiceName(value = "*", type = ApplicationService.class) |
| 72 | +public class FooHandler implements EventHandler { |
| 73 | + @Before @HandlerOrder(HandlerOrder.EARLY) |
| 74 | + void processBefore(CdsXxxEventContext context) { ... } |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +### Service Layer (`service/`) |
| 79 | + |
| 80 | +- `AttachmentService` - interface defining events: CREATE, READ, MARK_AS_DELETED, RESTORE |
| 81 | +- `DefaultAttachmentsServiceHandler` - default on-handler (stores in DB) |
| 82 | +- Malware scanning in `service/malware/` (optional, via SAP Malware Scanning Service) |
| 83 | + |
| 84 | +### Modification Event Factory |
| 85 | + |
| 86 | +`ModifyAttachmentEventFactory` selects the right strategy per attachment: `CreateAttachmentEvent`, `UpdateAttachmentEvent`, `MarkAsDeletedAttachmentEvent`, or `DoNothingAttachmentEvent`. |
| 87 | + |
| 88 | +### Configuration |
| 89 | + |
| 90 | +`Registration` implements `CdsRuntimeConfiguration` and wires everything: services, handlers, malware scanner, outbox, CSV paths. |
| 91 | + |
| 92 | +### CDS Model |
| 93 | + |
| 94 | +Defined in `cds-feature-attachments/src/main/resources/cds/com.sap.cds/cds-feature-attachments/`: |
| 95 | +- `attachments.cds` - `sap.attachments.Attachments` aspect, `MediaData` aspect, `StatusCode` enum, `ScanStates` entity |
| 96 | +- Generated CDS4J classes: `com.sap.cds.feature.attachments.generated` |
| 97 | + |
| 98 | +## Key Patterns |
| 99 | + |
| 100 | +| Pattern | Where | |
| 101 | +|---|---| |
| 102 | +| Constructor null-check | `requireNonNull(param, "param must not be null")` in every constructor | |
| 103 | +| Class-under-test var | `cut` in all unit tests | |
| 104 | +| Logging | `private static final Logger logger = LoggerFactory.getLogger(Foo.class)` | |
| 105 | +| Assertions | AssertJ (`assertThat(...)`) preferred over JUnit assertions | |
| 106 | +| Mocking | Mockito; tests follow Arrange/Act/Assert | |
| 107 | +| Error handling | `throw new ServiceException(ErrorStatuses.BAD_REQUEST, msg)` | |
| 108 | +| Outbox | Persistent outbox for delete operations (reliability) | |
| 109 | +| Thread-local | `ThreadLocalDataStorage` passes draft activation context | |
| 110 | + |
| 111 | +## Naming |
| 112 | + |
| 113 | +| Type | Convention | Example | |
| 114 | +|---|---|---| |
| 115 | +| Handler | `*Handler.java` | `ReadAttachmentsHandler` | |
| 116 | +| Unit test | `*Test.java` | `ReadAttachmentsHandlerTest` | |
| 117 | +| Integration test | `*IT.java` | `AWSClientIT` | |
| 118 | +| Event context | `*EventContext.java` | `AttachmentReadEventContext` | |
| 119 | + |
| 120 | +## Quality Gates |
| 121 | + |
| 122 | +All enforced in CI: |
| 123 | + |
| 124 | +- **JaCoCo:** 95% minimum (instruction, branch, complexity), 0 missed classes |
| 125 | +- **Mutation testing (Pitest):** 90% aggregated threshold on `handler.*` and `service.*` |
| 126 | +- **SpotBugs:** max effort, includes tests |
| 127 | +- **PMD:** SAP Cloud SDK rules, excludes generated code and tests |
| 128 | +- **Spotless:** Google Java Format check |
| 129 | + |
| 130 | +## CDS / CAP Tools |
| 131 | + |
| 132 | +- Use `cds-mcp` tool to search CDS model definitions before building queries or modifying models. |
| 133 | +- Use `cds-mcp` to search CAP documentation before using CAP APIs. |
| 134 | +- Generated CDS4J classes are in `com.sap.cds.feature.attachments.generated` -- do not hand-edit. |
0 commit comments