134 lines
14 KiB
Markdown
134 lines
14 KiB
Markdown
# PRD — arena-plm (standalone rebuild)
|
|
|
|
## Vision & scope
|
|
|
|
I am rebuilding the Arena PLM → SAP S/4HANA integration as a **proper SAP
|
|
application that lives in the tenant**. The predecessor (Express.js,
|
|
`~/projects/sap-apps/arena-plm`) works as a demo but fails the test that
|
|
matters: a business user inside S/4HANA cannot find it — not in the Fiori
|
|
launchpad, not in the Custom CDS Views app — because everything was built
|
|
side-by-side behind standalone URLs with ad-hoc access control.
|
|
|
|
The acceptance test I hold this rebuild to: **a business user finds the
|
|
application in the S/4HANA Fiori launchpad, finds its data in the Custom CDS
|
|
Views app, and access is governed by business roles** — with the side-by-side
|
|
footprint reduced to the one thing that cannot run in the tenant: Arena
|
|
connectivity.
|
|
|
|
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
|
|
of the old estate — one package at a time.
|
|
|
|
## Target architecture (ADR-002, 2026-09-04)
|
|
|
|
```
|
|
Arena PLM ──webhook + delta poll──▶ Connectivity worker (BTP CF, hardened TS)
|
|
│ no UI, no user URLs; technical user
|
|
reads approved / │ writes staged changes
|
|
executes sync ▼ ▼ via approval BO service binding
|
|
┌─ SAP S/4HANA Cloud Public (my429480) ─────────────────────────────────────┐
|
|
│ Z RAP BO "Arena Change Approval" ← staging + state machine + audit │
|
|
│ Fiori Elements List Report / Object Page ← in the tenant LAUNCHPAD │
|
|
│ IAM app → business catalog → business roles ← the only access control │
|
|
│ Custom CDS views over the BO (join I_Product, …) ← Custom CDS Views app │
|
|
│ Released OData APIs (Product/BOM/ChangeMaster/Attachment) ← sync targets │
|
|
└───────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Build state (2026-09-14):** the Fiori Elements UI layer is scaffolded as
|
|
`com.minicircuits.arenaplm` (List Report / Object Page, TS) in the structural `app/` subfolder
|
|
(sibling to `worker/`), running on a **mock** OData V4 service — an interim, generator-iterable
|
|
stand-in. The real on-stack RAP BO + service binding (ARN-002, V-2) and
|
|
launchpad deployment (ARN-007) remain gated on developer extensibility (V-1).
|
|
The predecessor `arena-plm` on CF is verified live (`/api/health` 200) and is
|
|
the base of record for the domain/field shape until the RAP service exists.
|
|
|
|
## Systems & boundaries
|
|
|
|
| System | Role | Boundary |
|
|
|---|---|---|
|
|
| SAP S/4HANA Cloud Public (`my429480`) | **Application host** (RAP BO, Fiori app, CDS views) and sync target | Developer extensibility (ABAP Cloud via ADT); released APIs only |
|
|
| Arena PLM (`api.arenasolutions.com/v1`) | Source of items, BOMs, changes, files | REST; webhook + delta poll, handled by the worker |
|
|
| Connectivity worker (BTP CF) | Arena connectivity + initial sync executor | Machine-to-machine only; technical user via communication arrangement |
|
|
|
|
## Interface contracts
|
|
|
|
Carried from the predecessor, in live use (2026-09-04); re-verify on first POC
|
|
touch. The worker keeps calling these on approval, so every KNOWLEDGE.md
|
|
tombstone remains valid.
|
|
|
|
| API | OData | Path | Notes |
|
|
|---|---|---|---|
|
|
| Product | V4 | `/sap/opu/odata4/sap/api_product/srvd_a2x/sap/product/0002` | deep insert for plant extensions |
|
|
| Product (plant fix) | V2 | `/sap/opu/odata/sap/API_PRODUCT_SRV` | `AvailabilityCheckType` is V2-only |
|
|
| BOM (write) | V2 | `/sap/opu/odata/sap/API_BILL_OF_MATERIAL_SRV;v=0002` | header first, then sequential items |
|
|
| BOM (read) | V2 | `/sap/opu/odata/sap/API_BILL_OF_MATERIAL_SRV` | v1 only; v2 rejects guid keys |
|
|
| Change Master | V2 | `/sap/opu/odata/sap/API_CHANGEMASTER;v=0002` | object-type assignments, material linking |
|
|
| Attachment | V2 | `/sap/opu/odata/sap/API_CV_ATTACHMENT_SRV` | function import for URL creation |
|
|
| Approval BO — UI binding (Fiori app) | V4 UI | `/sap/opu/odata4/sap/zzui_arena_change_apprvl000_o4/srvd/sap/zzui_arena_change_apprvl000_o4/0001/` (binding `ZZUI_ARENA_CHANGE_APPRVL000_O4`, generated 2026-09-15, unpublished) | expected namespace `com.sap.gateway.srvd.zzui_arena_change_apprvl000_o4.v0001`, alias `SAP__self`, entity `ChangeApproval_Type`/set `ChangeApproval`; confirm from live `$metadata` after publish (V-2); Fiori app still carries the pre-generation provisional name |
|
|
| Approval BO — Web API (A2X) binding (worker) | V4 Web API | binding `ZAPI_ARENA_CHANGE_APPROVAL_A2X` on definition `ZAPI_ARENA_CHANGE_APPROVAL` (pending: created after the A2X projection is active) | custom communication scenario, technical user; namespace `com.sap.gateway.srvd_a2x.zapi_arena_change_approval_a2x.v0001` expected; exposes create + read + `markExecuting` / `markSynced(SapChangeNumber)` / `markFailed(ErrorMessage)` (RAP-6) |
|
|
| Worker inbound surface | REST (OpenAPI 3.1) | `docs/api/worker.openapi.json` | webhook intake (503 when buffer full), health (`ok`/`degraded`, session `none/active/expired/refreshing`), sync-run admin (strict request schema); contract v0.2.0 (2026-09-14 wave); auth scheme pending OQ-6 (ARN-009) |
|
|
|
|
## Requirements
|
|
|
|
Capability level — field mappings deferred to the POC per my POC-before-spec rule.
|
|
|
|
| ID | Requirement | Status |
|
|
|---|---|---|
|
|
| ARN-001 | Sync chain PRODUCT → CHANGE_MASTER → BOM → DOCUMENTS in config-driven order, executed by the worker on approval | Planned |
|
|
| ARN-002 | Approval domain as an on-stack RAP BO: staging fields, state machine PENDING → APPROVED → EXECUTING → SYNCED \| FAILED, REJECTED terminal, FAILED → retrySync → EXECUTING (amended 2026-09-14: a terminal success state is required so an approved record is never executed twice); approve/reject/retrySync as RAP actions with instance feature control; audit fields (`RequestedBy`/`RequestedOn`/`DecidedBy`/`DecidedOn`); execution failure is a distinct state, never overloaded onto rejection (predecessor defect, `docs/predecessor-flow.md` §2) | Planned |
|
|
| ARN-003 | Durable persistence & audit — satisfied structurally by in-tenant RAP persistence (the predecessor lost its queue on every restart) | Planned (by design) |
|
|
| ARN-004 | Business mappings maintained in-tenant — evaluate Business Configuration maintenance objects (Custom Business Configurations app) before any file-based config | Planned |
|
|
| ARN-005 | Arena ingestion via webhook + delta poll in the connectivity worker | Planned |
|
|
| ARN-006 | Idempotent SAP writes, SAP-as-ledger (see `KNOWLEDGE.md`) — predecessor BOM/document syncs were non-idempotent; executors must check existence first | Planned |
|
|
| ARN-007 | Access exclusively via the Fiori launchpad with IAM app / business catalog / business roles; no user-facing standalone URLs | Planned |
|
|
| ARN-008 | Approval data discoverable via custom CDS views, joinable to released views (the discoverability test); look up join targets with `object_type=CDS_STOB` in `sap-released-objects` (no `DDLS` type in the public_cloud dataset, KNOWLEDGE 2026-09-14) | Planned |
|
|
| ARN-009 | API-first: every interface this package owns carries an OpenAPI 3.1 JSON contract under `docs/api/`, authored before or with the change; implementation conforms to the contract | Adopted (2026-09-10) |
|
|
| ARN-010 | The approved payload is the executed payload: the executor writes the staged data the approver saw — never re-fetch-and-recompute at execution time (the predecessor discarded the preview, making approval decorative; `docs/predecessor-flow.md` §2) | Adopted (2026-09-10) |
|
|
|
|
### RAP-track requirements harvested from the UI (2026-09-14)
|
|
|
|
Derived while binding the Fiori app; each becomes a `rap-developer` brief
|
|
once V-1 opens the development tenant.
|
|
|
|
| ID | Requirement | Source |
|
|
|---|---|---|
|
|
| RAP-1 | Behavior definition declares `approve`, `reject`, `retrySync` with `( features : instance )` and implements `get_instance_features` so the UI service emits `Core.OperationAvailable`; approve/reject only for PENDING, retrySync only for FAILED. `approve` writes no `SapChangeNumber` (execution does). The CDS emits numeric `StatusCriticality` 2/2/5/3/1/1 for PENDING/APPROVED/EXECUTING/SYNCED/REJECTED/FAILED (5 = Information is V4-only) | [source: abap-docs /abap-docs-standard/ABENBDL_ACTIONS_FC; sap-docs /abap-fiori-showcase/01_general_features#operations-and-actions, verified 2026-09-14] |
|
|
| RAP-2 | `reject` takes a mandatory `RejectReason` (char 255) parameter; `approve`/`retrySync` return `$self`; the entity is read-only from the UI (no create/update/delete) | UI contract (annotation.xml, mock metadata) |
|
|
| RAP-3 | `Status` carries a text element (`@ObjectModel.text.element`, `@UI.textArrangement: #TEXT_ONLY`) so the UI shows text, not codes | [source: fiori-mcp-server "Text and Text Arrangement", verified 2026-09-14] |
|
|
| RAP-4 | Semantic key `ItemNumber` (`@ObjectModel.semanticKey`); `Status` and `RequestedOn` sortable/filterable | UI default variant |
|
|
| RAP-5 | Two service bindings on definition `ZUI_ARENA_CHANGE_APPROVAL`: OData V4 **UI** binding `ZUI_ARENA_CHANGE_APPROVAL_O4` for the app and an OData V4 **Web API** binding for the worker; the binding name sets the URL first segment and the namespace; hand back the live `$metadata` of the UI binding to reconcile (V-2) | [source: sap-docs sap-help loio 5717c0a1dafc4335add0207b81c39cef, 5f45f125dfe84c20beb18f5de1512f5a, verified 2026-09-14] |
|
|
| RAP-6 | Worker-callable execution-state actions on the A2X binding — `markExecuting`, `markSynced` (sets `SapChangeNumber`), `markFailed` (sets `ErrorMessage`) — with instance feature control so the UI never offers Approve on an executing record | [source: abap-docs /abap-docs-cloud/ABENBDL_ACTIONS_FC, verified 2026-09-14] |
|
|
| RAP-7 | Staged payload (`SapPreview`) is `abap.string` — CDS char elements are capped at 1333 characters and truncation would break ARN-010 | [source: abap-docs /abap-docs-cloud/ABENCDS_SELECT_LIST_ENTRY_V2, verified 2026-09-14] |
|
|
| RAP-8 | Field `DecidedBy` (not `ApprovedBy`) holds approver or rejecter; semantic key `ItemNumber, ChangeType, ArenaEcoId` | UI contract |
|
|
|
|
## Architecture decisions
|
|
|
|
- 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.
|
|
|
|
## Verification items & open questions
|
|
|
|
| ID | Item | Status |
|
|
|---|---|---|
|
|
| V-1 | Developer-extensibility access on the development tenant | **Closed 2026-09-15** — `my431353.s4hana.cloud.sap`: business user AZAW holds `ZBR_DEVELOPER` (SAP_BR_DEVELOPER template), `ZBR_ADMINISTRATOR_SW_DEV`, `ZBR_DEVELOPMENT_MANAGER_DIN` and five more (live: `sap-api users getRoles`, verified 2026-09-15). V-1b done 2026-09-15 (destination `0M7DEJI`, MCP lists it). Role correct (A4C catalogs). V-1b **closed 2026-09-15**: package `ZARENA_PLM` under `ZLOCAL`; probe class created and activated via ADT MCP |
|
|
| V-2 | Custom communication scenario can expose the approval BO's A2X service to the worker's technical user; and the Fiori app's annotation namespace, `_Type` entity-type suffix and UI-binding URL segment are reconciled from the live `$metadata` of the UI binding (decided 2026-09-14; the mock cannot verify this) | Open |
|
|
| V-3 | On-stack Application Jobs vs worker-side polling for the Arena delta | Open — flow findings 2026-09-10: Arena's outbound-integration queue holds the cursor (`reconciled` flag) and is the clean delta mechanism; `/changes`-feed polling needs client-side date filtering (`docs/predecessor-flow.md` §1) |
|
|
| V-4 | Can a Claude Code agent outside the VS Code editor author ABAP source through the ADT MCP Server? | **Answered 2026-09-15: no.** `create_object` and the generators take structure, not source (live probe); SAP's editing MCP tool is planned for Public Edition 2702 [source: sap-docs loio 7f716223a88c40e0992777c8d9febccf, verified 2026-09-15]. Build plan: `x-ui-service` generator for the BO skeleton, source edits handed over as files for the VS Code editor until 2702 |
|
|
| OQ-5 | Long-term: move the sync executor on-stack (released ABAP APIs) vs keep it in the worker — worker initially | Open |
|
|
| OQ-6 | Webhook receiver hosting and auth for the worker on CF | Open |
|
|
|
|
## Status
|
|
|
|
| Work item | State |
|
|
|---|---|
|
|
| Package home + governance | Done (2026-09-04) |
|
|
| Developer environment | Done (2026-09-04); MCP loadout revised to ABAP/RAP set (done 2026-09-04) |
|
|
| Ground-truth enforcement kit (ADR-003 hooks) | Done (2026-09-04); hardened 2026-09-14 — Bash/MultiEdit/filesystem writes gated, grounding-only marker refresh, portable paths, fail-closed, 37 pipe-tests green |
|
|
| Specialist agent roster (5 agents, docs/agent-roster.md) | Done (2026-09-04; all 5 files YAML-verified in .claude/agents/) |
|
|
| V-1…V-3 verification POC | Planned — V-1 (ADT access on my429480) is the user-side gate for everything on-stack |
|
|
| Fiori Elements app (`app/`, mock-bound) | Done for the mock stage (2026-09-14) — gateway service shape (binding-derived identity), six-state domain, polished List Report/Object Page, launchpad inbound `ArenaChangeApproval-manage`; SAP review findings closed. Deploy gated on V-1/V-2 (live `$metadata` reconciliation) |
|
|
| RAP BO (approval domain) | In progress — skeleton generated and active in `ZARENA_PLM` (2026-09-15, ATC clean); **waiting on owner: paste `docs/handover/rap/` sources in VS Code per its README**, then I activate/ATC/create the A2X BDEF + binding; IAM app/catalog and publishing are the next brief |
|
|
| Connectivity worker | Review wave Done (2026-09-14) — TTL wiring, cursor-after-success, buffer-full = tick failure, health conformance, strict JSON-only validation, bounded buffer, graceful drain, HTTP timeout, fixed-phrase errors; 137 tests green incl. the schema-driven contract-conformance suite. Next: Arena client POC (live), executor leg gated on V-2. **Do not deploy the scaffold**: the ingest buffer has no consumer yet, so a long-running instance would answer 503 after `WEBHOOK_QUEUE_MAX_SIZE` events. Next: Arena client POC (live), executor leg gated on V-2 |
|
|
| Worker API contract (`docs/api/worker.openapi.json`) | v0.2.1 Done (2026-09-14) — health enums/`degraded`/`poller`, strict `SyncRunRequest`, webhook 503, 413/415 + `default` on every operation, reserved 502, `DOCUMENTS` token; `x-sap-stateInfo: beta`, provisional webhook schema pending Arena POC |
|