ADR-005: OQ-11 closed — Integration Suite native (ADK adapter + iFlows + SBPA)

Both options framed for OQ-11 failed the deciding criterion: whether the
next person finds the thing inside the platform. A CAP service or a
hardened worker on Cloud Foundry is discoverable only to whoever already
knows the route to it, which is ADR-002's original objection relocated
rather than answered.

The integration is now Integration Suite native. Nothing on Cloud
Foundry, nothing in ABAP:

- Arena connectivity as a custom adapter built with the Adapter SDK —
  sender adapter with the webhook endpoint and delta scheduler, cluster
  lock for single-flight login, ADK persistency for the delta cursor,
  tenant user credentials for Arena secrets.
- Movement as iFlows to the released Product / BOM / ChangeMaster /
  Attachment OData APIs.
- Human approval in SAP Build Process Automation (entitled in the global
  account, not yet assigned).

Decisive: every mechanism hand-rolled in worker/ has a first-class ADK
facility, so the adapter deletes that custom infrastructure rather than
merely relocating it; and the ADK's Java/Maven/OSGi toolchain is not a
new cost here, because the AS/400 FetchAPI servlets are already Java and
Java developers can be staffed in-house.

worker/ is reclassified from deliverable to specification: its 137 tests
describe the Arena session, delta-cursor and webhook behaviour the
adapter must reproduce. app/ has no target service under ADR-005 and is
kept as reference, unrepointed.

ADR-004's "side-by-side runtime" is narrowed to mean "in Integration
Suite". New verification items V-5 (can an ADK adapter hold an Arena
session under cluster lock — the first build) and V-6 (where SBPA tasks
surface for a business user).

No SAP tenant or BTP artifact was modified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 11:22:05 -07:00
co-authored by Claude Opus 5
parent ffd33f4ec0
commit 272a202152
3 changed files with 195 additions and 32 deletions
+78
View File
@@ -2,6 +2,84 @@
Append-only decision log for this package. Append-only decision log for this package.
## 2026-09-29 — ADR-005: OQ-11 closed. Integration Suite native — Arena ADK adapter + iFlows, approval in SAP Build Process Automation
- What changed: I closed OQ-11 and wrote
`docs/adr/ADR-005-integration-suite-native.md`. The integration becomes
Integration Suite native: an Arena custom adapter built with the Adapter SDK
(sender adapter carrying the webhook endpoint and the delta scheduler), iFlows
for the movement to the released Product / BOM / ChangeMaster / Attachment
APIs, and human approval in SAP Build Process Automation. Nothing runs on
Cloud Foundry; nothing is written in ABAP. I rewrote the PRD's target
architecture accordingly and added V-5 and V-6.
- Why: both options I had framed for OQ-11 failed the criterion that actually
decides this. The test is not build cost, it is whether the next person finds
the thing inside the platform — and a CAP service or a hardened worker on
Cloud Foundry is discoverable only to whoever already knows the route to it,
which is ADR-002's original objection relocated rather than answered.
Two findings then chose between the native options:
- Every mechanism I hand-rolled in `worker/` has a first-class ADK facility:
cluster lock for single-flight login, ADK persistency for the delta cursor,
user credentials for Arena secrets, scheduler support, connection status,
tracing, endpoint visualization, and versioning rules [source: SAP Help,
*Adapter Development Process*, Cloud Integration, verified 2026-09-29]. The
adapter does not merely present better; it deletes the infrastructure the
worker existed to supply.
- I had recorded the ADK's Java/Maven/OSGi toolchain as the cost of this
route. It is not a cost in this estate: the AS/400 FetchAPI servlets on
`mcl2000` are already Java, and Java developers can be staffed in-house. One
language and one team span both ends, and the ADK covers the on-premise leg
directly through *Accessing On-Premise Application using Cloud Connector* —
which retires the deleted Cloud Foundry `fetchapi-bridge` pattern instead of
rebuilding it.
- Affected: PRD (target architecture, decisions, OQ-11 closed, V-5 and V-6
added), new ADR-005, ADR-004 narrowed. `worker/` is reclassified from
deliverable to specification; `app/` has no target service under ADR-005 and
is kept as reference, not repointed. No SAP tenant or BTP artifact was
modified.
- Decision: ADR-005. I also correct something I asserted too confidently
earlier in the day: that SAP Build Process Automation tasks surface in the
Fiori launchpad. That is now V-6, unverified — what I can state is that the
service is entitled in the global account (`process-automation`,
`process-automation-service`) and therefore needs assigning, not buying.
First build is V-5: a minimal Arena sender adapter that logs in and holds the
session under cluster lock. Nothing else starts before it.
## 2026-09-29 — Read access to the customizing tenant proven through `mc-s4hana`; the parked password is simply stale
- What changed: nothing in the tenant — I established how to read it. Through
the BTP destination `mc-s4hana`, three read-only GETs against
`my429480` all answered 200: `API_BUSINESS_PARTNER/$metadata` (EDMX v1.0,
65 entity sets), `A_BusinessPartner?$top=1` (BusinessPartner `1710`), and
`api_product/srvd_a2x/sap/product/0002/$metadata` (EDMX 4.0, 39 entity sets).
I used the destination service instance `sap-apps-dest` and its existing
service key `dest-anywhere-dest-key`; I created no key and no instance.
- Why: after retargeting, direct basic auth to the customizing tenant returned
401, and I needed to know whether the tenant was refusing the user or the
stored password was wrong.
- Affected: no SAP object, no BTP artifact. Knowledge only.
- Findings:
- `mc-s4hana` authenticates as **`BasicAuthentication` with the same user,
`AZ_API_USER`**, and succeeds. So the tenant accepts that user over basic
auth: the 401 was neither a lockout nor a user problem. The password in
`_shared/.env.starter-cust-my429480.bak` is stale, and the working value is
already held by the destination. No credential reset is needed.
- The destination's own description reads "SAP S/4HANA Public Cloud - MC
Production" while its URL is the starter customizing tenant — the same
mislabel this package carried, now visible in BTP as well. I left it alone;
it is shared, and a description is not worth an unrequested change.
- `default-env.json` alone does not work with SAP Cloud SDK v4:
`@sap-cloud-sdk/connectivity` 4.6.0 resolves bindings through `@sap/xsenv`'s
`filterServices()`, which reads `process.env.VCAP_SERVICES` and never loads
the file. `require('@sap/xsenv').loadEnv()` must run ahead of the SDK
requires (or `VCAP_SERVICES` be exported). The first attempt failed with
"Could not find service binding of type 'destination'".
- Decision: I will not copy the working password out of the destination into
`.env`. The destination is the sanctioned path for this estate, so the fix is
to make the shared CLI destination-aware rather than to hold a second copy of
a credential. Until that is done, reads against the customizing tenant go
through a destination-based call, not through `sap-api`.
## 2026-09-29 — Tooling retargeted to the starter customizing tenant; its credential is rejected ## 2026-09-29 — Tooling retargeted to the starter customizing tenant; its credential is rejected
- What changed: - What changed:
+35 -31
View File
@@ -28,43 +28,44 @@ In scope: material, BOM, change-master, and document sync from Arena to
S/4HANA, gated by a human approval workflow. Out of scope: every other package S/4HANA, gated by a human approval workflow. Out of scope: every other package
of the old estate — one package at a time. of the old estate — one package at a time.
## Target architecture (ADR-004, 2026-09-29 — supersedes ADR-002) ## Target architecture (ADR-005, 2026-09-29 — closes OQ-11; narrows ADR-004)
The starter system's **customizing** tenant `my429480` (client 100) supports Integration Suite native. Nothing on Cloud Foundry, nothing in ABAP. The
**key-user extensibility only** — no ABAP, no RAP. ABAP development requires customizing tenant `my429480` (client 100) supports key-user extensibility only
the starter system's **development** tenant `my431353` (client 080), which I — no ABAP, no RAP — so the on-stack RAP business object of ADR-002 has no home
parked on 2026-09-29 [source: fiori-tools-samples `misc/s4hana/README` there [source: fiori-tools-samples `misc/s4hana/README`, "Tenant Types",
"Tenant Types", verified 2026-09-29]. The on-stack RAP business object of verified 2026-09-29]; and a custom application on Cloud Foundry fails the test
ADR-002 therefore has no home in the tenant I am now working in, and the that matters, which is whether the next person finds it inside the platform.
application moves back out to a side-by-side runtime consuming released APIs.
``` ```
Arena PLM ──webhook + delta poll──▶ Connectivity worker (BTP CF, hardened TS) ┌─ SAP Integration Suite · Cloud Integration ───────────────────────────────┐
│ built, 137 tests green, NOT deployed │ Arena custom adapter (Adapter SDK, Java/OSGi) │
▼ │ · sender: webhook endpoint + delta scheduler │
Approval store + state machine + audit │ · cluster lock -> single-flight Arena login │
(side-by-side — host is the open call, OQ-11) │ · ADK persistency -> delta cursor │
│ │ · user credentials -> Arena secrets from the tenant store │
Fiori Elements List Report / Object Page │ iFlows -> movement: material, BOM, change master, documents │
(`app/` — already built, service-repointable) └──────────────┬──────────────────────────────────┬─────────────────────────┘
│ released OData APIs, mc-s4hana │ released OData APIs │ approval request
┌─ Starter system · CUSTOMIZING tenant `my429480` (client 100) ─────────────┐ ▼ ▼
│ Product / BOM / ChangeMaster / Attachment released APIs ← sync targets │ ┌─ Starter system · CUSTOMIZING tenant `my429480` ─┐ ┌─ SAP Build Process ──┐
│ Key-user extensibility + configuration only — no ABAP, no RAP │ │ Product / BOM / ChangeMaster / Attachment APIs │ │ Automation │
│ Launchpad reachability for the app: decided with OQ-11 │ │ Key-user extensibility + configuration only │ │ human approval task │
└───────────────────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────┘ │ (entitled, unassigned)│
└──────────────────────┘
parked 2026-09-29 ──▶ Starter system · DEVELOPMENT tenant `my431353` (080) parked ──▶ Starter system · DEVELOPMENT tenant `my431353` (client 080)
19 RAP objects live in ZARENA_PLM, left in place 19 RAP objects live in ZARENA_PLM, left in place
spec ──▶ worker/ — 137 tests describe the Arena behaviour to reproduce
ref ──▶ app/ — no target service under ADR-005; kept, not repointed
``` ```
**Build state (2026-09-29).** What exists: the Fiori Elements UI **Build state (2026-09-29).** Nothing from this package has ever been deployed
`com.minicircuits.arenaplm` in `app/`, built and bound to a mock OData V4 to Cloud Foundry or reached a business user. What exists: the connectivity
service; the connectivity worker in `worker/`, built with 137 tests green and worker (built, 137 tests green, never deployed, now the specification for the
never deployed (no deployment descriptor was ever written); and 19 activated adapter); the Fiori Elements app in `app/` (built, mock-bound, no longer the
RAP objects on the parked development tenant, with their sources kept in UI route); and 19 activated RAP objects on the parked development tenant, with
`docs/handover/rap/` as reference. Nothing from this package has ever been sources kept in `docs/handover/rap/`.
deployed to Cloud Foundry or reached a business user.
## Systems & boundaries ## Systems & boundaries
@@ -130,6 +131,7 @@ once V-1 opens the development tenant.
- ADR-001 — toolchain-must-engage rebuild; Express predecessor reference-only. **Amended by ADR-002.** - ADR-001 — toolchain-must-engage rebuild; Express predecessor reference-only. **Amended by ADR-002.**
- ADR-002 — on-stack first: RAP + Fiori Elements in the tenant; side-by-side reduced to a connectivity worker; CAP exits the architecture. **Superseded by ADR-004.** - ADR-002 — on-stack first: RAP + Fiori Elements in the tenant; side-by-side reduced to a connectivity worker; CAP exits the architecture. **Superseded by ADR-004.**
- ADR-005 (2026-09-29) — **closes OQ-11**: Integration Suite native. Arena custom adapter (Adapter SDK) + iFlows for movement; human approval in SAP Build Process Automation; nothing on Cloud Foundry, nothing in ABAP. Narrows ADR-004's "side-by-side runtime" to mean "in Integration Suite". `worker/` becomes the specification, not a deliverable.
- ADR-004 (2026-09-29) — I withdraw the on-stack RAP route and move the application back to a side-by-side runtime against released APIs. Two facts force it: the customizing tenant `my429480` (client 100) supports key-user extensibility only, and I am no longer willing to carry an ABAP/RAP build for this package. I park the development tenant `my431353` (client 080) with its 19 activated objects in place rather than delete them, so the route stays reversible. The replacement host — key-user extensibility in the tenant versus a CAP service side-by-side — is OQ-11; my recommendation is CAP, because the connectivity worker must be side-by-side regardless and one runtime beats two. - ADR-004 (2026-09-29) — I withdraw the on-stack RAP route and move the application back to a side-by-side runtime against released APIs. Two facts force it: the customizing tenant `my429480` (client 100) supports key-user extensibility only, and I am no longer willing to carry an ABAP/RAP build for this package. I park the development tenant `my431353` (client 080) with its 19 activated objects in place rather than delete them, so the route stays reversible. The replacement host — key-user extensibility in the tenant versus a CAP service side-by-side — is OQ-11; my recommendation is CAP, because the connectivity worker must be side-by-side regardless and one runtime beats two.
## Verification items & open questions ## Verification items & open questions
@@ -146,7 +148,9 @@ once V-1 opens the development tenant.
| OQ-10 | Ownership of UI annotations: the backend metadata extension `ZC_CHANGEAPPROVAL` or the app's local `annotation.xml`. Today 35 of the 58 local annotations override a backend annotation with the same target, term and qualifier (layering rule [source: fiori-mcp-server "Visualizing and Managing Annotations with SAP Fiori Tools - Service Modeler", verified 2026-09-16]), so a DDLX change to those terms is invisible in the app. The local file adds i18n labels, action criticality, the `#Default` variants and the facet IDs the OPA journey relies on | Open (2026-09-16). Interim rule: a term defined locally is changed locally. I consolidate before launchpad deployment | | OQ-10 | Ownership of UI annotations: the backend metadata extension `ZC_CHANGEAPPROVAL` or the app's local `annotation.xml`. Today 35 of the 58 local annotations override a backend annotation with the same target, term and qualifier (layering rule [source: fiori-mcp-server "Visualizing and Managing Annotations with SAP Fiori Tools - Service Modeler", verified 2026-09-16]), so a DDLX change to those terms is invisible in the app. The local file adds i18n labels, action criticality, the `#Default` variants and the facet IDs the OPA journey relies on | Open (2026-09-16). Interim rule: a term defined locally is changed locally. I consolidate before launchpad deployment |
| OQ-8 | Per-operation authorization for the approval BO. Today it is `authorization master ( none )`: any holder of the UI app can approve, reject and retry, and any tenant ABAP code can create and mark* through EML. SAP Help calls `( none )` "not recommended in real-world scenarios". The target is `( global )` with a `FOR GLOBAL AUTHORIZATION` handler and `AUTHORITY-CHECK OBJECT` on a custom authorization object: decisions for business roles, create/mark* for the communication role. First verify that custom authorization objects can be created on `my431353` [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION, ABAPHANDLER_METH_GLOBAL_AUTH; sap-docs sap-help loio 673c05562e144702a080c574c3da2da3, verified 2026-09-16 by my review] | Open (2026-09-16): does not block the dev-tenant UI POC; must close before any business role other than the developer's gets the app (IAM brief) | | OQ-8 | Per-operation authorization for the approval BO. Today it is `authorization master ( none )`: any holder of the UI app can approve, reject and retry, and any tenant ABAP code can create and mark* through EML. SAP Help calls `( none )` "not recommended in real-world scenarios". The target is `( global )` with a `FOR GLOBAL AUTHORIZATION` handler and `AUTHORITY-CHECK OBJECT` on a custom authorization object: decisions for business roles, create/mark* for the communication role. First verify that custom authorization objects can be created on `my431353` [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION, ABAPHANDLER_METH_GLOBAL_AUTH; sap-docs sap-help loio 673c05562e144702a080c574c3da2da3, verified 2026-09-16 by my review] | Open (2026-09-16): does not block the dev-tenant UI POC; must close before any business role other than the developer's gets the app (IAM brief) |
| OQ-7 | Tenant object naming and cleanup for the approval BO | **Closed 2026-09-16.** The package was deleted in ADT, contents and package itself (verified live through ADT MCP validation, 2026-09-16). I build from scratch, without the generator: table `ZCHANGEAPPROVAL`, `ZR_CHANGEAPPROVAL`, `ZBP_R_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL`, SRVD `ZUI_ARENA_CHANGE_APPROVAL` with SRVB `ZUI_ARENA_CHANGE_APPR_O4`, and SRVD `ZAPI_ARENA_CHANGE_APPROVAL` with SRVB `ZAPI_ARENA_CHANGE_APPR_A2X`. Binding names follow SAP's 26-character limit (RAP-5). Entity set is `ChangeApproval`; the A2X projection and parameter entity names are unchanged | | OQ-7 | Tenant object naming and cleanup for the approval BO | **Closed 2026-09-16.** The package was deleted in ADT, contents and package itself (verified live through ADT MCP validation, 2026-09-16). I build from scratch, without the generator: table `ZCHANGEAPPROVAL`, `ZR_CHANGEAPPROVAL`, `ZBP_R_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL`, SRVD `ZUI_ARENA_CHANGE_APPROVAL` with SRVB `ZUI_ARENA_CHANGE_APPR_O4`, and SRVD `ZAPI_ARENA_CHANGE_APPROVAL` with SRVB `ZAPI_ARENA_CHANGE_APPR_A2X`. Binding names follow SAP's 26-character limit (RAP-5). Entity set is `ChangeApproval`; the A2X projection and parameter entity names are unchanged |
| OQ-11 | Where the approval store, state machine and audit live now that ADR-004 withdrew the RAP BO. Option A: key-user extensibility in the customizing tenant (custom business object + low-code UI) — stays in the tenant and in the launchpad natively, but the Arena connectivity still needs an outside worker, so the application ends up with two homes, and key-user objects are transport-bound. Option B: a CAP service side-by-side on BTP CF — one runtime with the worker, matches the archetype the rest of my estate already runs, and `app/` repoints to it cheaply because 35 of its 58 annotations are already local (OQ-10); the cost is BTP runtime and launchpad reachability becomes a federation question. | Open (2026-09-29). I recommend Option B. Decide before any further build. | | OQ-11 | Where the approval store, state machine and audit live now that ADR-004 withdrew the RAP BO. | **Closed 2026-09-29 by ADR-005.** Neither of the options I framed survived the deciding criterion — a custom app on Cloud Foundry is discoverable only to whoever already knows the route to it, which is ADR-002's original objection relocated. The answer is Integration Suite native: an Arena adapter built with the Adapter SDK plus iFlows for the movement, and SAP Build Process Automation for the human approval. Decisive evidence: every mechanism `worker/` hand-rolled has an ADK facility (cluster lock, ADK persistency, user credentials, scheduler, connection status, tracing, endpoint visualization) [source: SAP Help *Adapter Development Process*, verified 2026-09-29]; and the ADK's Java/OSGi toolchain is not a new cost, because the AS/400 FetchAPI servlets are already Java and Java developers can be staffed in-house. |
| V-5 | POC: can an Adapter SDK sender adapter hold an Arena session (`POST /login` -> `arenaSessionId`, 25-minute TTL) under ADK cluster lock, and persist the delta cursor through ADK persistency? This is the first build and the gate on ADR-005. `worker/` is the behavioural specification | Open (2026-09-29) |
| V-6 | Where SAP Build Process Automation approval tasks surface for a business user, and whether they can be reached from the S/4HANA Fiori launchpad rather than only SAP Build's own inbox. This is what remains of the original acceptance test | Open (2026-09-29) |
| OQ-12 | The ABAP/RAP-dependent items V-2, V-3, OQ-5, OQ-8, OQ-9 and OQ-10 are all scoped to the parked development tenant. They are **parked with ADR-004**, not closed; each returns only if the RAP route is revived. | Parked (2026-09-29) | | OQ-12 | The ABAP/RAP-dependent items V-2, V-3, OQ-5, OQ-8, OQ-9 and OQ-10 are all scoped to the parked development tenant. They are **parked with ADR-004**, not closed; each returns only if the RAP route is revived. | Parked (2026-09-29) |
## Status ## Status
@@ -0,0 +1,81 @@
# ADR-005 — OQ-11 closed: Integration Suite native — Arena ADK adapter + iFlows, approval in SAP Build Process Automation
Date: 2026-09-29 · Status: Accepted (closes OQ-11; narrows ADR-004)
## Context
ADR-004 withdrew the on-stack RAP route and said the application moves to a
side-by-side runtime against released APIs, leaving the host open as OQ-11:
key-user extensibility in the tenant, or a CAP service on Cloud Foundry.
Both of those options failed the criterion that actually decides this. The test
is not build cost — it is whether the next person finds the thing inside the
platform. A CAP service or a hardened worker on Cloud Foundry is discoverable
only to whoever already knows the route to it, which is the same objection that
produced ADR-002 in the first place, merely relocated. Custom applications
living outside the platform are not acceptable here.
Two findings then settled which native option to take.
**The Adapter Development Kit already provides the infrastructure my worker
invented.** Every non-trivial mechanism in `worker/` has a first-class ADK
facility [source: SAP Help, *Adapter Development Process*, Cloud Integration,
verified 2026-09-29]:
| Hand-rolled in `worker/` | ADK facility |
|---|---|
| Promise lock so only one Arena login runs; correctness dependent on `instances: 1` | Managing Cluster Lock in Custom Adapters |
| Delta cursor persistence | Enabling ADK Persistency |
| Arena credentials in environment / a user-provided service | Accessing User Credentials |
| Delta poll timer | Enabling Scheduler Support for ADK Sender Adapter |
| `/api/health` with `ok`/`degraded` | Enabling Connection Status for Integration Flow |
| Structured logging | Enabling Tracing for Custom Adapter |
| Webhook ingress URL | Enabling Endpoint Visualization for Custom Adapter |
So the adapter does not merely present better — it deletes the custom
infrastructure the worker existed to supply.
**Java is not a new skill for this estate.** The ADK is a Java, Maven and OSGi
toolchain, which I had recorded as the cost of this route. It is not a cost
here: the AS/400 FetchAPI servlets on `mcl2000` are already Java, and Java
developers can be staffed from inside the company. One language and one team
therefore span both ends of the estate, and the ADK covers the on-premise leg
directly through *Accessing On-Premise Application using Cloud Connector* —
the sanctioned route to `mcl2000`, which retires the deleted Cloud Foundry
`fetchapi-bridge` pattern rather than rebuilding it.
## Decision
The integration is Integration Suite native. Nothing runs on Cloud Foundry and
nothing is written in ABAP.
- **Arena connectivity** is a custom adapter built with the Adapter SDK: a
sender adapter carrying the webhook endpoint and the delta scheduler, using
cluster lock for single-flight login, ADK persistency for the delta cursor,
and the tenant's user credentials for Arena secrets.
- **Movement** is iFlows: Arena → the released S/4 OData APIs for Product, BOM,
Change Master and Attachment.
- **Human approval** is SAP Build Process Automation, which is already entitled
in the global account (`process-automation`, `process-automation-service`), so
it requires assignment rather than procurement.
- **The S/4 target** remains released OData APIs through the customizing tenant
`my429480`.
`worker/` stops being a deliverable and becomes the **specification**: its 137
tests describe the Arena session, delta-cursor and webhook behaviour the adapter
must reproduce. That is worth more than its code, and it is why ADR-004 kept it.
## Consequences
- ADR-004's phrase "a side-by-side runtime" is narrowed: there is no custom
application runtime at all. Side-by-side now means "in Integration Suite",
not "on Cloud Foundry".
- The Fiori Elements app in `app/` has no target service under this decision.
Approval screens come from SAP Build Process Automation. I keep `app/` as
reference rather than deleting it, on the same reasoning as the parked RAP
objects, and I do not repoint it.
- New verification items: V-5 (can an ADK adapter hold an Arena session under
cluster lock) and V-6 (where SAP Build Process Automation tasks surface for a
business user).
- The estate gains a second use for the same skill: adapters for `softco-ap`
and the AS/400 legs can follow the same pattern.