This project implements a CAP (Node.js) service that ingests discovery JSON payloads, persists data, enforces tenant isolation from JWT claims, and exposes OData V4 APIs for fit-gap consumption.
POST /odata/v4/discovery/SystemsGET /odata/v4/discovery/SystemsGET /odata/v4/discovery/Systems(<id>)/scopetitems
- CAP model in
db/schema.cdswith:Systemsparent entityScopeItemschild entity (composition)tenant_idon every row- unique constraint on
(systemId, tenant_id)for idempotency
- CAP service in
srv/discovery-service.cdsexposed on/discovery - Runtime logic in
srv/discovery-service.js:- tenant resolution from JWT/CAP context (not from payload)
- validation for
systemId(missing, empty, over 50 chars -> 400 with specific error code) - idempotent create/update behavior for duplicate
systemIdper tenant - tenant filtering for reads
- explicit 403 for cross-tenant access to a known system
- XSUAA descriptor in
xs-security.json - Cloud Foundry MTA in
mta.yaml(service module + HANA deployer)
- Node.js 20+
- SAP BTP Trial subaccount with:
- Cloud Foundry enabled
- HANA Cloud instance + HDI entitlement
- XSUAA entitlement
- Cloud Foundry CLI (
cf) - MultiApps plugin for CF CLI (
cf deploy) - Make utility in PATH (required by
mbton Windows)
npm install
npx cds deploy --to sqlite:db.sqlite
npx cds watchService base URL (local): http://localhost:4004/discovery
For local mocked auth, provide a tenant via x-tenant-id header so tenant-aware handlers can persist/read data.
- Log in to Cloud Foundry:
cf login -a https://api.cf.<region>.hana.ondemand.com
cf target -o <org> -s <space>- Build CAP artifacts:
npm ci
npx cds build --production- Build MTAR:
npx mbt build -t gen --mtar cap-discovery-ingestion.mtar- Deploy MTAR:
cf deploy gen/cap-discovery-ingestion.mtar- Verify:
cf apps
cf servicesIf XSUAA creation fails with Invalid xsappname: xsappname in xs-security.json must be a plain string (letters, digits, -, _, / only). Placeholders like ${org} / ${space} are not allowed by the XSUAA broker.
If HANA / HDI creation fails with There is no database available for your space: in BTP cockpit, open your HANA Cloud instance and map it to the same Cloud Foundry org/space you deploy to (or create a HANA database in that subaccount first). Until a database exists for that space, hdi-shared cannot be provisioned.
curl -X POST "http://localhost:4004/discovery/Systems" \
-u alice: \
-H "x-tenant-id: tenant-a" \
-H "Content-Type: application/json" \
--data-binary "@sample-payload.json"curl -X GET "http://localhost:4004/discovery/Systems" \
-u alice: \
-H "x-tenant-id: tenant-a"curl -X GET "https://<app-route>/odata/v4/discovery/Systems"curl -X GET "https://<app-route>/odata/v4/discovery/Systems(<system-uuid-from-tenant-a>)" \
-H "Authorization: Bearer <token-tenant-b>"- Missing
systemId->400, code:DISCOVERY_SYSTEM_ID_REQUIRED - Empty
systemId->400, code:DISCOVERY_SYSTEM_ID_REQUIRED systemIdlength over 50 ->400, code:DISCOVERY_SYSTEM_ID_TOO_LONG
cf appsshowing deployed app- API evidence:
- POST success
- GET success
- request without token (
401) - cross-tenant request (
403)
- HANA Cloud DB Explorer rows where
tenant_idis populated in:task4_db_Systemstask4_db_ScopeItems
- CAP build succeeded locally (
npx cds build --production). - CF deployment could not be executed here because:
cfCLI was not installed in PATH.mbtfailed becausemakewas not installed in PATH on Windows.