With this tutorial, you learn how to enhance the core application as described in the first tutorials for deployment. You can either enhance the core application to a deployable multi-tenant solution following the step-by-step guide below or you can fast-forward and deploy the main-multi-tenant branch.
If you want to start right away with a working multi-tenant implementation, clone the branch main-multi-tenant and start deploying it.
To fast-forward:
-
In the development subaccount SAP BTP cockpit (subaccount level), navigate to Instances and Subscriptions, open SAP Business Application Studio, and open the dev space PoetrySlams created during the Prepare Your SAP Business Technology Platform Account for Development.
-
Use the tile Clone from Git on the Welcome view to clone this GitHub repository (https://github.com/SAP-samples/partner-reference-application) and switch to the branch main-multi-tenant.
-
You can now deploy the multi-tenant application to the provider SAP BTP account.
In this approach, you use the core application as developed in the previous parts of this tutorial and add changes to enable deployment as a multi-tenant application (as contained in the branch main-multi-tenant).
Therefore, open the Partner Reference Application you developed before in the SAP Business Application Studio of your development account.
Follow the steps described in this section to enhance your application. Additionally, find detailed information in
Make some adjustments to ensure that the application can be deployed to SAP BTP Cloud Foundry runtime as a central launchpad component.
-
Adopt the ./app/poetryslams/webapp/manifest.json.
-
Ensure that the service name is defined in the web app configuration file ./app/poetryslams/webapp/manifest.json.
Note: This service name must be unique within your account and will appear in the runtime URL of the application.
"sap.cloud": { "service": "poetryslammanager", "public": true }
-
In the dataSources section, adopt the
uri
by removing the/
beforeodata
. The URI of the data sources is changed now to a relative path."dataSources": { "mainService": { "uri": "odata/v4/poetryslamservice/", "type": "OData", "settings": { "annotations": [], "odataVersion": "4.0" } } }
-
-
Do the same for the ./app/visitors/webapp/manifest.json of the Visitors application accordingly.
When creating the CAP project using the wizard in the tutorial Develop the Core of the SAP BTP Application, several files were created that include the configuration for modules and resources required for multi-tenancy:
- The folder app/router containing an implemented approuter (also called standalone approuter).
- The file mtx/sidecar/package.json providing a module to handle multitenancy, feature toggles and extensibility.
- The file mta.yaml in the root folder, containing required modules and resources.
- The package.json file in the root folder.
Now, follow the next steps to make further required changes:
-
Go to the mta.yaml file in the root folder. Note that a correct indentation is important in this file.
-
Replace all occurrences of the string
partner-reference-application
withpoetry-slams
. This makes the names of the created service instances more consistent. You can also create a meaningful description. -
Enhance the build parameters to install the node modules with the CDS development kit and copy the common data model json which is required for SAP Build Work Zone before the build.
build-parameters: before-all: # Defines the build parameter - builder: custom commands: - npm ci --omit=dev # [Workzone] Create resources folder and copy cdm.json - mkdir -p resources - cp workzone/cdm.json resources/cdm.json - npx -p @sap/cds-dk cds build --production
-
Add and configure the destination content module. This is where you define destinations and service keys for the destinations that are automatically created in the provider subaccount.
Note that the subpath poetryslammanager in the attribute
URL
of the destinationpoetry-slams-cdm
below must match the value in the fieldservice
of the objectsap.cloud
defined in the files ./app/poetryslams/webapp/manifest.json ./app/visitors/webapp/manifest.json.modules: # Destinations # Creates destination in subaccount of type OAuth2ClientCredentials to access HTML5 repo - name: poetry-slams-destinations-content type: com.sap.application.content requires: - name: poetry-slams-html5-runtime parameters: service-key: name: poetry-slams-html5-runtime-key - name: poetry-slams-destination parameters: content-target: true build-parameters: no-source: true parameters: content: subaccount: existing_destinations_policy: update destinations: - Name: poetry-slams-cdm Description: Destination for the workzone configuration of solution poetryslammanager ServiceInstanceName: poetry-slams-html5-runtime ServiceKeyName: poetry-slams-html5-runtime-key URL: https://html5-apps-repo-rt.${default-domain}/applications/cdm/poetryslammanager # Adds workzone configuration of solution poetryslammanager
-
Go to the
poetry-slams-srv
module.- Replace the
builder
module npm with npm-ci. - Replace the name
srv-api
in "provides
" withpoetry-slams-srv-api
.
- Replace the
-
Replace the
poetry-slams-app-deployer
module with the following content:# App UI content deployer module # Uploads the static content of the HTML5 application and deploys it to the HTML5 repository - name: poetry-slams-app-content type: com.sap.application.content path: . requires: - name: poetry-slams-srv-api - name: poetry-slams-auth - name: poetry-slams-html5-repo-host parameters: content-target: true parameters: config: destinations: - forwardAuthToken: true name: poetry-slams-srv-api url: ~{poetry-slams-srv-api/srv-url} build-parameters: build-result: resources requires: - artifacts: - poetryslams.zip name: poetryslams target-path: resources/ - artifacts: - visitors.zip name: visitors target-path: resources/
-
Go to the
poetry-slams-mtx
module and replace the list with the required services by the following services. This does two things: It enables the mtx module to handle the subscription of the required services and changes theSUBSCRIPTION_URL
delimiter from (-) to (.), which allows you to use generic routes for all tenants.requires: - name: poetry-slams-db - name: poetry-slams-auth - name: poetry-slams-registry - name: poetry-slams-destination - name: poetry-slams-html5-repo-host - name: app-api properties: SUBSCRIPTION_URL: ~{app-protocol}://\${tenant_subdomain}.~{app-uri}
-
Go to the
poetry-slams
module (app router).-
Add a route to support the generic tenant routing (with (.) delimiter):
parameters: keep-existing-routes: true routes: - route: '*.${default-uri}' # generic route for all subscriptions
-
Adjust the properties to adopt the
TENANT_HOST_PATTERN
to fit the (.) delimiter and add properties for Content-Security-Policy and Cross-Origin Resource Sharing (CORS):properties: TENANT_HOST_PATTERN: '^(.*).${default-uri}' # prettier-ignore httpHeaders: "[{ \"Content-Security-Policy\": \"default-src 'self' https://sapui5.hana.ondemand.com; frame-ancestors 'self' https://*.hana.ondemand.com; object-src 'none';\"}]" CORS: - uriPattern: .* allowedOrigin: - host: '*.${default-uri}' protocol: 'https'
-
Replace
srv-api
in the "requires
" section withpoetry-slams-srv-api
(2 occurrences).Note: This name must be identical to the destination name defined in the ./app/poetryslams/xs-app.json.
-
Add
redirect-uris
to the properties of the provided functionapp-api
:provides: - name: app-api properties: app-protocol: ${protocol} app-uri: ${default-uri} redirect-uris: ${protocol}://*.${default-uri}/** # Redirect URI to connect modules running on different Cloud Foundry landscapes (e.g. eu10 / eu10-004)
-
-
Adjust the destination service resource (poetry-slams-destination). This includes the poetry-slams-srv-api as defined in the destination for the route as defined in the web application configuration files ./app/poetryslams/xs-app.json and ./app/visitors/xs-app.json in the
requires
section.Note: There will be two destinations created that are required for the SAP Build Work Zone integration: the runtime destination of the launchpad and the destination to access the poetry slams service module.
resources: # Destination service # Offers a predefined configuration that simplifies connecting to the service - name: poetry-slams-destination type: org.cloudfoundry.managed-service requires: - name: poetry-slams-srv-api - name: poetry-slams-auth parameters: service: destination service-plan: lite config: init_data: subaccount: existing_destinations_policy: update destinations: - Name: poetry-slams-rt Description: Runtime destination of the launchpad, required for workzone Authentication: NoAuthentication ProxyType: Internet Type: HTTP URL: https://${org}.launchpad.${default-domain} # Runtime destination of launchpad, required for workzone CEP.HTML5contentprovider: true - Name: poetry-slams-srv-api Description: Destination to access the poetry slams service module, required for workzone Authentication: NoAuthentication ProxyType: Internet Type: HTTP URL: https://${org}-${space}-poetry-slams-srv.${default-domain} # Destination to access the poetry slams service module, required for workzone HTML5.DynamicDestination: true HTML5.ForwardAuthToken: true HTML5Runtime_enabled: false
-
Go to the
poetry-slams-auth
resource.-
Change the service plan from
application
tobroker
. This will give you more flexibility when extending the application functionality later.parameters: service-plan: broker
-
Add
app-api
to therequires
list:requires: - name: app-api
-
In case the approuter and the authorization service are running in different Cloud Foundry landscapes (for example,
eu10
andeu10-004
), theoauth2
configuration needs to support this:parameters: config: oauth2-configuration: redirect-uris: - ~{app-api/redirect-uris} # Redirect for approuter, required if xsuaa and approuter are running on different Cloud Foundry landscapes (e.g. eu10 / eu10-004)
-
-
Go to the
poetry-slams-registry
resource and change thedisplayName
,description
, andcategory
configurations. These are used by subscriber subaccounts to find the application:parameters: config: displayName: Poetry Slam Manager description: Manage poetry slam events and bookings of artists and visitors. category: 'Applications / Multi-Customer Partner Solutions'
-
After you've applied the changes described above in the file mta.yml, this is what the file will look like: the MTA file of the sample application.
Note: There can be differences in comments or the sequence of entries. However, be aware that a correct indentation is required.
-
-
In the folder app/router:
-
File package.json: You can remove the 'engines' field from the originally created file. It sets the node version that is not required since the available node version during runtime is defined by SAP Cloud Foundry and updated automatically on a regular basis.
-
default-env.json: You can delete this file. It is intended for local testing but not required. It is ignored by the .gitignore file of this repository anyway.
-
Go to the app router config file located in the app/router folder (xs-app.json). Ensure that the file is as follows:
{ "welcomeFile": "poetryslams/", "routes": [ { "source": "^/-/cds/.*", "destination": "mtx-api", "authenticationType": "none" }, { "source": "^(.*)$", "target": "$1", "service": "html5-apps-repo-rt", "authenticationType": "xsuaa" } ] }
-
-
In the Poetry Slams application routing config file that is located in the app/poetryslams folder (xs-app.json), route the default path to the
index.html
file and offer a path to the OData service. Remove the routes that are not required. You defined the destination poetry-slams-srv-api before as part of the project configuration mta.yml file. Ensure that the application xs-app.json config file is as follows:{ "welcomeFile": "/index.html", "authenticationMethod": "route", "routes": [ { "source": "^/odata/v4/poetryslamservice/(.*)$", "target": "/odata/v4/poetryslamservice/$1", "destination": "poetry-slams-srv-api", "authenticationType": "xsuaa", "csrfProtection": true }, { "source": "^(.*)$", "target": "$1", "service": "html5-apps-repo-rt", "authenticationType": "xsuaa" } ] }
Note: The order of routes is crucial as the most specific one must come first.
-
In this project, the implemented approuter uses the index.html file located in the /app/poetryslams/webapp/ folder to serve the web page. Copy the files initAppStyle.css and index.html into the folder /app/poetryslams/webapp/util/ of your project to avoid inline style definitions and content security policy violations:
-
Repeat steps 3 and 4 for the Visitors application (see index.html, initAppStyle.css and xs-app.json).
-
Ensure that the scope
mtcallback
is available in the xs-security.json. Check the documentation for more details: XSUAA.:"scopes": [ { "name": "$XSAPPNAME.mtcallback", "description": "Subscription via SaaS Registry", "grant-as-authority-to-apps": [ "$XSAPPNAME(application,sap-provisioning,tenant-onboarding)" ] } ]
-
Adjust the package.json in the root folder.
- Ensure that the profile mtx-sidecar is available. For more information, check the documentation: SaaS Registry Dependencies:
"cds": { "profile": "mtx-sidecar" }
- Additionally, rename
partner-reference-application
in the undeploy step topoetry-slams
.
-
Adjust the package.json of the mtx module by adding the required services:
"cds": { "profile": "mtx-sidecar", "requires": { "auth": "xsuaa", "destinations": true, "html5-host": { "vcap": { "label": "html5-apps-repo", "plan": "app-host" }, "subscriptionDependency": { "uaa": "xsappname" } } } }
The CDS libraries are offered as npm modules in the package.json. After the creation of the SAP Cloud Application Programming Model (CAP) project using the wizard, the npm rimraf module is added to the ./package.json as a development dependency. Move this module to the dependencies section. This facilitates the handling of the command npm run build
.
SAP Build Work Zone is used as a central launchpad for the Partner Reference Application. To be content provider for SAP Build Work Zone, a common data model (CDM) needs to be defined. The common data model defines the design-time business content of the application.
To add the CDM to your application, follow these steps:
-
Create a folder under the root folder of your project named workzone.
-
Copy the cdm.json into the newly created workzone folder. This creates a group with the applications poetryslams and visitors and two roles during the SAP Build Work Zone configuration that is done during the provisiong of a customer subaccount. The texts-sections are required for translation.
Your project is now consistent with the main-multi-tenant branch. You can deploy the multi-tenant application to the provider SAP BTP account.