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 PartnerReferenceApplication created during the Prepare Your SAP BTP 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
uriby 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-applicationwithpoetry-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. The destination
poetry-slams-cdmis a Common Data Model (CDM) design time destination, which points to the location of the stored CDM in the HTML5 repository.Note that the subpath poetryslammanager in the attribute
URLof the destinationpoetry-slams-cdmbelow must match the value in the fieldserviceof the objectsap.clouddefined 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-srvmodule.- Replace the
buildermodule npm with npm-ci. - Replace the name
srv-apiin "provides" withpoetry-slams-srv-api.
- Replace the
-
Replace the
poetry-slams-app-deployermodule 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-mtxmodule 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_URLdelimiter 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-slamsmodule (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_PATTERNto 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-apiin 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-uristo 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
requiressection.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. The
poetry-slams-rtis a Common Data Model (CDM) runtime destination which points to the Approuter URL. For detailed instructions, see Developing HTML5 Business Solutions as Content Providers -> Procedure -> Step 2: Define destinations (provider subaccount)-> Runtime Destination on SAP Help Portal.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 # Required for dynamic tiles in Work Zone HTML5.DynamicDestination: true HTML5.ForwardAuthToken: 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-authresource.-
Change the service plan from
applicationtobroker. This will give you more flexibility when extending the application functionality later.parameters: service-plan: broker
-
Add
app-apito therequireslist:requires: - name: app-api
-
In case the approuter and the authorization service are running in different Cloud Foundry landscapes (for example,
eu10andeu10-004), theoauth2configuration 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-registryresource and change thedisplayName,description, andcategoryconfigurations. 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:
-
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.htmlfile 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
mtcallbackis available in the xs-security.json."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 about SaaS Registry Dependencies.
"cds": { "profile": "mtx-sidecar" }
- Additionally, rename
partner-reference-applicationin 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.