HARD RULES (NEVER VIOLATE)
- Never touch the source project. All migration work happens exclusively inside
appfront-migrated/. The source directory is read-only — never edit, delete, or overwrite any file outsideappfront-migrated/. - Never assume the auth service. Always read
xs-security.json(orias-security.json) and everyxs-app.jsonbefore deciding XSUAA vs IAS. The source may mix both. - Never apply html5-repo migration rules to a Neo source. Neo uses a different MTA structure (
neo-mta.yaml, parameters-based artifacts). Check first. HTML5Runtime_enabled: trueon a destination-service resource must be removed. Its presence signals html5-apps-repo usage. appFront does not use this property.- The
destination-contentmodule must be removed entirely. This module creates instance-level destinations with service keys — a pattern only used by html5-apps-repo. appFront's deployer module binds directly to service instances. - The
app-contentmodule'srequireslist must include all backend service instances directly. Not via destination mapping. Credentials injected into the running approuter come from directrequires. - Never change
xs-app.jsonauthenticationTypeon any route without explicit user confirmation of the target auth service. Wrong authenticationType = 401 in production. - If the source uses
sap.cloud.servicein a destination-content module, flag this as a WorkZone integration pattern requiring additional CDM steps. Document it clearly in the migration plan and wait for user acknowledgment before proceeding. - Resource and service naming must use the
sap.cloud.serviceprefix (without dots). Given prefixP(dots stripped):- Resource name:
P-<service>(e.g.comsapfavorites-app-front,comsapfavorites-xsuaa) service-nameparameter:P-<service>-service(e.g.comsapfavorites-app-front-service)- Never invent arbitrary names. Never reuse the source app names. Always derive from the
sap.cloud.servicevalue extracted in Phase 1a-naming.
- Resource name:
- Always ask for the backend URL when the backend exists. Only emit
<<REPLACE_WITH_REAL_BACKEND_URL>>when the user explicitly says the URL is not yet known. This placeholder is intentionally invalid — it will cause an MTA build error, forcing the user to replace it before deploying. - Never add
redirect-uristo generatedxs-security.json. appFront does not require them — omit the field entirely, even if the source had them.
Source Type Identification (MANDATORY FIRST STEP)
Before anything else, identify the source type by examining the project structure:
html5-apps-repo (managed approuter) indicators:
mta.yamlcontains a module withtype: com.sap.application.contentandparameters.content.subaccount.service-keysorparameters.content.subaccount.instances- A resource of type
org.cloudfoundry.managed-servicewith servicehtml5-apps-repoand planapp-host - A resource of type
org.cloudfoundry.managed-servicewith servicedestination(HTML5Runtime destination) xs-app.jsonroutes reference destinations pointing to html5-apps-repo URLs
SAP Neo HTML5 App indicators:
- A
neo-mta.yamlorneoUpdated.mtarartifact parameters.jsonwith SAP Cloud Platform Neo-style properties- No Cloud Foundry org/space references in the MTA
- HTML5 app zip artifact deployed to SAP Neo HTML5 Applications Runtime service
WorkZone managed approuter indicators:
xs-app.jsonhas routes withservice: "approuter-extension"or similar Managed Approuter patternsmta.yamlmodule withsap.cloud.servicein destination-content- A
cdm.jsonor similar CDM (Content Deployment Manifest) file
Standalone approuter (localDir) indicators:
mta.yamlcontains a module withtype: approuter.nodejs- The approuter module's
pathdirectory containsxs-app.jsonwith routes that have"localDir"properties - No
html5-apps-reporesource anywhere inmta.yaml - No
destination-contentmodule - Backend destinations are injected via
group: destinationsin the approuter'srequiresblock - Typically co-located with a CAP backend (
type: nodejs) and HDI deployer (type: hdb)
Load Reference Index First
At the start of every migration session, load references/INDEX.md. This index tells you which reference files to load for each decision branch. Only load the specific reference files relevant to the current migration — do not load all of them.
Fetching Live Documentation
Load references/online-docs.md at the start of every session. It contains a curated index of SAP Help Portal URLs mapped to migration phases.
When to fetch a URL:
- The local reference file for the current phase is marked
🔲 Placeholderinreferences/INDEX.md - A question arises that the local references do not clearly answer
- The user explicitly asks about official documentation
How to fetch:
- Use
WebFetchwith the relevant URL fromreferences/online-docs.md - Fetch only the page relevant to the current phase — do not fetch all URLs upfront
- Use the fetched content in-context only; do not write it to disk
- If the page returns no content (some SAP Help Portal pages require authentication), fall back to local references or training knowledge and inform the user
Migration Workflow
Phase 0 — Discovery (MANDATORY)
0a — Locate the MTA root
Determine the working directory for the migration:
# Check if mta.yaml exists in the current directory
ls mta.yaml neo-mta.yaml 2>/dev/null || echo "NOT_IN_ROOT"
# If not found, search subdirectories (up to 3 levels deep)
find . -maxdepth 3 \( -name "mta.yaml" -o -name "neo-mta.yaml" \) 2>/dev/null
- If
mta.yamlis found in the current directory: the project root is. - If
mta.yamlis found in a subdirectory (e.g../my-project/mta.yaml): the project root is that subdirectory. Inform the user: "I foundmta.yamlat./my-project/mta.yaml. I will run the migration from that directory." - If no
mta.yamlis found anywhere: STOP. Ask the user — "I could not find anmta.yamlin this directory or any subdirectory. Please confirm the project path or navigate to the project root and retry."
0b — Copy source to appfront-migrated/
Immediately copy the entire source project into appfront-migrated/ at the same level as the project root. Do this without asking — the source is never touched.
# SOURCE_ROOT = the project root identified in 0a (e.g. . or ./my-project)
# Copy everything, preserving structure, excluding any existing appfront-migrated folder
cp -r <SOURCE_ROOT>/. appfront-migrated/
# Remove any copied node_modules — native binaries do not survive cp and mbt build runs npm install
find appfront-migrated/ -maxdepth 3 -name "node_modules" -type d -prune -exec rm -rf {} \; 2>/dev/null || true
If appfront-migrated/ already exists, inform the user and ask whether to overwrite it before proceeding.
From this point on, all file reads for analysis use the source, and all file writes and edits target appfront-migrated/ exclusively.
0c — Source Type Detection
Scan the source project for the indicators in the "Source Type Identification" section above.
# Find all mta.yaml files
find <SOURCE_ROOT> -name "mta.yaml" -o -name "neo-mta.yaml" 2>/dev/null
# Find all xs-app.json files
find <SOURCE_ROOT> -name "xs-app.json" 2>/dev/null
# Find all xs-security.json / ias-security.json files
find <SOURCE_ROOT> -name "xs-security.json" -o -name "ias-security.json" 2>/dev/null
# Check for html5-apps-repo resource type
grep -r "html5-apps-repo" <SOURCE_ROOT> --include="*.yaml" -l 2>/dev/null
# Check for standalone approuter
grep -r "approuter.nodejs" <SOURCE_ROOT> --include="*.yaml" -l 2>/dev/null
# Check for localDir routes in xs-app.json
grep -r '"localDir"' <SOURCE_ROOT> --include="*.json" -l 2>/dev/null
# Check for Neo indicators
find <SOURCE_ROOT> -name "neo-mta.yaml" -o -name "parameters.json" 2>/dev/null
Document your findings: Source type: [neo | html5-repo | managed-approuter | standalone-approuter]
0d — Target Runtime and Auth Service
Ask the user these BLOCKING questions one at a time. Wait for the answer before asking the next. Present choices as a numbered list so the user can reply with a number.
Question 1 — Source type (confirm or correct your detection from 0c):
I detected the source type as [detected type]. Is that correct?
- Yes, that's correct
- No — it's Neo
- No — it's html5-repo (managed approuter)
- No — it's standalone approuter
Question 2 — Target runtime:
Which runtime should the migrated app deploy to?
- Cloud Foundry (CF)
- Kyma
Question 3 — Auth service:
Which auth service should the migrated app use?
- XSUAA
- IAS
- Keep existing (same as source)
Question 4 — Backend type (ask for each backend destination found in xs-app.json / neo-app.json, one at a time — skip ui5 and test-resources):
For each destination <dest-name>:
What type of backend is
<dest-name>?
- SAP BTP backend (same BTP subaccount — CF app, CAP service, etc.)
- External / on-prem backend (outside BTP, or a different BTP subaccount)
- No backend (frontend-only app — skip destinations entirely)
Destination methodology based on backend type:
-
BTP backend (answer 1):
- Use a configuration destination — defined in the deployer module's
parameters.config.destinationsblock inmta.yaml - No destination service resource needed in
mta.yaml - Set
forwardAuthToken: trueon the destination entry - Ask for the backend URL:
What is the URL for
<dest-name>? (e.g.https://myapp.cfapps.eu12.hana.ondemand.com)
- Use a configuration destination — defined in the deployer module's
-
External / on-prem backend (answer 2):
- Use a destination service resource in
mta.yaml(service: destination,service-plan: lite) - Define the destination in
init_data.subaccount.destinationswithAuthentication: NoAuthentication— do not ask for or configure authentication credentials; the user will add them later in the BTP Cockpit - Ask for the backend URL (use
<<REPLACE_WITH_REAL_BACKEND_URL>>only if the user explicitly says the URL is not yet known):What is the URL for
<dest-name>? (leave blank if not yet known) - If blank, emit
<<REPLACE_WITH_REAL_BACKEND_URL>>as the URL value
- Use a destination service resource in
-
No backend / frontend-only (answer 3):
- Before dropping any routes, list every destination found in the source and ask for explicit confirmation:
I will omit the following destination routes since you selected frontend-only:
/<path>→<dest-name>(repeat for each destination route found inneo-app.json/xs-app.json)
Is that correct, or do any of these need to be kept?
- Only proceed after the user confirms. If the user wants to keep a route, treat that destination as a BTP or external backend and ask Question 4 for it individually.
- Before dropping any routes, list every destination found in the source and ask for explicit confirmation:
Question 5 — Backend migration status (ask only for BTP backends where the URL is not yet known):
Has the BTP backend for
<dest-name>already been deployed?
- Yes — already deployed (I will provide the URL)
- No — not yet deployed (use placeholder URL for now)
Question 6 — XSUAA instance (ask only if auth service is XSUAA):
Should the migration create a new XSUAA service instance, or bind to an existing one?
- Create a new XSUAA instance
- Bind to an existing instance
If the user chooses 2 — existing instance, ask:
What is the name of the existing XSUAA service instance?
Then ask:
Please list the existing scopes defined in that XSUAA instance (paste the
scopesarray from itsxs-security.json, or list scope names). This is needed to avoid conflicts and to determine which new scopes must be added for the migrated app.
0e — Workaround Detection
Note any of these conditions that require special handling:
sap.cloud.servicein destination-content → WorkZone integration (loadreferences/troubleshooting/workzone-integration.md)- IAS-only source (
ias-security.jsonpresent, noxs-security.json) → IAS migration path (loadreferences/services/ias-config.md) - Multiple
xs-app.jsonfiles → multi-module app (document all modules) - Kyma target → load
references/target-configs/kyma-deployment.md
Phase 1 — Baseline Analysis (MANDATORY)
Read from the source project and document the current state. All analysis is read-only against the source.
1a — Read all configuration files:
- All
mta.yamlfiles (full content) - All
xs-app.jsonfiles (full content of each) xs-security.jsonorias-security.json(full content)- All
manifest.jsonfiles (extractsap.cloud.service— see naming convention below) - For Neo sources:
neo-app.json(full content — extractroutes,welcomeFile,cacheControl,responseHeaders,logoutPage, and allsecurityConstraintsentries)
1a-naming — Extract sap.cloud.service for resource naming (MANDATORY)
Run:
# Handles both flat "sap.cloud.service" and nested "sap.cloud": { "service": ... } formats
grep -r '"service"' . --include="manifest.json" -A2 -B2 | grep -A1 '"sap.cloud"'
# Also try:
grep -r 'sap\.cloud' . --include="manifest.json" -l
Read each matching manifest.json and locate the value at sap.cloud.service (either as a flat key or nested under "sap.cloud": { "service": "..." }).
Then:
-
Collect all
sap.cloud.servicevalues found across allmanifest.jsonfiles. -
If multiple values differ — STOP. All apps in the same MTA must share one
sap.cloud.service. Report the conflict and ask the user which value to use. -
If no
sap.cloud.serviceis found (always the case for Neo sources) — this is expected for Neo apps. Explain the concept and ask:"
sap.cloud.servicedoes not exist in Neo. In appFront, this value defines a business solution — a logical grouping of one or more HTML5 apps sharing a single XSUAA instance and a singleapp-frontservice instance.Are you migrating this app as part of a larger group of Neo apps that belong to the same product or team?
- No — migrate this app as a standalone solution
- Yes — I want to group multiple Neo apps into one business solution (mass migration)
In either case, please provide a
sap.cloud.servicevalue for this solution (e.g.com.sap.myteam,com.company.hr). Choose a namespace that represents the whole product, not just this single app."If the user chooses mass migration (option 2), ask:
"Please list all the Neo app directories (or paths) you want to include in this business solution. I will create a single
mta.yamlwith one deployer module and one shared XSUAA instance for all of them." Then follow the mass migration pattern inreferences/migration-guides/neo-to-appfront.md(Mass Migration section). -
Strip all dots from the value to form the naming prefix (e.g.
com.sap.favorites→comsapfavorites).
Use this prefix for ALL resource and service names in the migrated mta.yaml (see Hard Rule #9 below).
1b — Build a Findings Table:
| Item | Current Value | Migration Action Needed |
|---|---|---|
| MTA modules | List each module name and type | |
| Resources | List each resource name and service | |
| html5-repo app-host resource | Present / Absent | Remove if present |
| destination-content module | Present / Absent | Remove if present |
| HTML5Runtime_enabled flag | Present / Absent | Remove if present |
| xs-app.json authenticationMethod | value | Keep / Change |
| Route authenticationType | List each | Keep / Change per route |
| sap.cloud.service usage | Present / Absent | Flag for WorkZone steps |
| Neo securityConstraints (Neo sources only) | List each permission value from all securityConstraints entries in neo-app.json |
Map each to a XSUAA scope in xs-security.json |
1c — Load source-type reference:
- html5-repo source → load
references/source-types/html5-repo-app.md(modeling type identification),references/source-types/saas-approuter-creds-handling.md(full credential chain details for the detected type), andreferences/migration-guides/html5-repo-to-appfront.md - Neo source → load
references/source-types/neo-html5-app.mdandreferences/migration-guides/neo-to-appfront.md - Standalone approuter source → load
references/source-types/standalone-approuter.mdandreferences/migration-guides/standalone-approuter-to-appfront.md - Load the relevant target config reference:
references/target-configs/cf-xsuaa-mta.yaml.mdorreferences/target-configs/cf-ias-mta.yaml.mdorreferences/target-configs/kyma-deployment.md
Phase 2 — Migration Plan Checkpoint (MANDATORY — no changes to appfront-migrated/ before user confirms)
The source has already been copied to appfront-migrated/. Now present the exact changes that will be applied inside appfront-migrated/ to complete the migration:
Files to MODIFY in appfront-migrated/:
| File | Changes |
|---|---|
mta.yaml |
List exact changes: modules to add/remove/modify, resources to add/remove/modify |
xs-app.json |
List exact property changes |
xs-security.json |
List exact changes (or "no changes needed") |
Files to DELETE from appfront-migrated/:
| File | Reason |
|---|---|
| (list files if any) |
Files to CREATE in appfront-migrated/:
| File | Content |
|---|---|
| (list new files needed, e.g. Kyma yaml files) |
WorkZone / CDM steps required: (list if applicable)
Then present this plan to the user and ask:
Does this migration plan look correct? Should I proceed with these changes? (yes to continue / no to adjust)
⛔ STOP HERE until the user explicitly says yes. Do not modify any file in appfront-migrated/ before receiving confirmation.
Phase 3 — Execute Migration
Only proceed after Phase 2 confirmation.
3a — Update mta.yaml
For Neo → appFront (CF) migration, first load and read references/migration-guides/neo-to-appfront.md in full, then create mta.yaml from scratch following its Step 4 template exactly:
- The MTA must contain an
app-frontresource (service: app-front,service-plan: developer) — neverhtml5-apps-repo app-host - The
app-contentdeployer module requires theapp-frontresource withcontent-target: true, plus XSUAA and destination resources - Add
deploy_mode: html5-repoto the MTA rootparametersblock - Destination configuration — apply the methodology determined in Phase 0d Question 4:
- BTP backend → configuration destination: add a
parameters.config.destinationsblock to the deployer module withforwardAuthToken: trueand the backend URL. Do NOT add a destination service resource. - External/on-prem backend → destination service resource: add
comsaplibrary-destinationresource (service: destination,service-plan: lite) withinit_data.subaccount.destinationscontaining one entry per external destination (Authentication: NoAuthentication, URL from user or placeholder). Do NOT configure credentials — they are added later in the BTP Cockpit. - The
ui5entry (https://ui5.sap.com) always goes inconfig.destinationson the deployer module regardless of backend type — it is never in the destination serviceinit_data.
- BTP backend → configuration destination: add a
- Replace
html5-apps-repoapp-hostresource withapp-frontresource (service:app-front, plan:developer— always usedeveloper, never any other value) - Remove the
destination-contentmodule entirely - In the
app-contentmodule (renamed toapp-front-deployeror similar):- Change
typefromcom.sap.application.contenttocom.sap.application.content(type stays, but parameters change) - Remove
parameters.content.subaccount.service-keysentries referencing html5-repo destinations - Add
requiresentries for each service instance the app needs credentials from (XSUAA, backend OData service, etc.) - Remove
HTML5Runtime_enabled: truefrom destination resource parameters
- Change
- Keep the destination service resource only for external/on-prem backends (as determined in Phase 0d Question 4). BTP backends use
config.destinationson the deployer module — no destination service resource needed.
For standalone approuter (localDir) → appFront (CF) migration, apply these structural changes:
- Remove the
approuter.nodejsmodule entirely - Add an HTML5 source module (
type: html5) for each UI app directory that was served vialocalDir - Add an
app-contentdeployer module (type: com.sap.application.content) with:requiresentries for XSUAA and any other bound services (the credentials injected into appFront)content-target: trueon theapp-frontresource referenceconfig.destinationsblock listing backend API destinations (replaces thegroup: destinationsfrom the old approuterrequires)
- Add an
app-frontresource (service: app-front,service-plan: developer) - Keep the CAP backend (
type: nodejs), HDI deployer (type: hdb), XSUAA resource, and HANA resource completely unchanged - Load
references/migration-guides/standalone-approuter-to-appfront.mdfor the complete step-by-step guide with annotated before/after examples
Load examples/appfront-target-mta-xsuaa.yaml or examples/appfront-target-mta-ias.yaml as the canonical target reference.
3a-neo-cleanup — Neo source pre-processing (Neo sources only)
Before making any other changes to appfront-migrated/, apply these Neo-specific cleanup steps:
-
Handle
-dbg.jsfiles — Neo cockpit exports without source access produce both a minified file and a-dbg.jsdebug copy incontroller/(and other folders). The-dbg.jsfile is the full source; the non-debug counterpart is incomplete or minified. Fix this:- Scan for all
*-dbg.jsfiles:find appfront-migrated/ -name "*-dbg.js" - For each
-dbg.jsfile found: delete the corresponding non-debug.jsfile (same name without-dbg), then rename the-dbg.jsfile by removing the-dbgsuffix - On macOS/Linux run:
for f in $(find appfront-migrated/ -name "*-dbg.js"); do base="${f%-dbg.js}.js"; rm -f "$base"; mv "$f" "$base" done - On Windows, perform the equivalent rename manually or via PowerShell
- Scan for all
-
Update
manifest.json_version— Neo apps commonly have"_version": "1.1.0"or"1.2.0". Update to:"_version": "1.65.0" -
build:cfscript — Thepackage.jsonbuild:cfscript must only containui5 build --dest dist. Useui5-task-zipperinui5.yaml(withadditionalFiles: [xs-app.json]) to packagexs-app.jsoninto the zip cross-platform. Do NOT use shell commands for copying or zipping —cp,zip -r, andmvfail on Windows.
3b — Update xs-app.json
- For routes serving static HTML5 content: add
"service": "app-front"property - For standalone approuter sources: replace every
"localDir"route property with"service": "app-front". ThelocalDirkey must be removed entirely — it is not a valid property in appFront's xs-app.json and will be silently ignored, causing 404s on static content - For Neo sources: load and read
references/migration-guides/neo-to-appfront.mdthen createxs-app.jsonfrom scratch following its Step 6 template exactly. The file must include:/resourcesand/test-resourcesroutes pointing to theui5destination withauthenticationType: none- One route per backend destination from
neo-app.jsonwithauthenticationType: xsuaaand the matchingscope - A catch-all route
^(.*)$with"service": "app-front"— never omit this, it is what serves the static app content
- Remove all Neo-specific route types (
type: applicationwithname: sapui5preview,type: servicewithname: sapui5)
- Ensure
authenticationMethodat root matches the target auth service (XSUAA ="route", IAS varies) - For routes with
authenticationType: confirm with user which routes should be"xsuaa","ias", or"none"before changing - Load
references/target-configs/xs-app-patterns.mdfor the correct pattern per auth service - For Neo sources with
cacheControlinneo-app.json: translate eachcacheControlentry to a"cacheControl"property on the matching route inxs-app.json(direct mapping — appFront's runtime supports this property). If the source has a root-levelcacheControlarray with path-based entries, map eachpathpattern to the most specific matching route. Surface any entries that cannot be mapped to a specific route and ask the user how to handle them.
3c — Update xs-security.json (if auth service changes)
- XSUAA → IAS switch: the
xsappnamefield moves to IAS application, scopes/role-templates may need restructuring - Load
references/services/xsuaa-config.md(XSUAA) orreferences/services/ias-config.md(IAS) for exact patterns
3d — Kyma-specific files (if target is Kyma)
Load references/target-configs/kyma-deployment.md and create:
ServiceInstance.yamlfor app-front serviceServiceBinding.yamlfor credential mountingAPIRule.yamlfor routingFunction.yamlor deployment yaml for the app content
Phase 4 — Critic Review (MANDATORY)
Before writing the final report, spawn a critic sub-agent using the Task tool with this prompt:
You are a migration critic reviewing a completed SAP appFront migration. The user has just migrated an HTML5 application from [SOURCE_TYPE] to appFront on [TARGET_RUNTIME] with [AUTH_SERVICE] auth.
Review the migration against these checks. For each check, say PASS, WARN, or FAIL and explain briefly:
1. SERVICE REMOVAL (html5-repo source only): Were all three html5-repo components removed?
- destination-content module (should not exist in migrated mta.yaml)
- html5-apps-repo app-host resource (should not exist)
- HTML5Runtime_enabled: true on destination service parameters (should not exist)
2. REQUIRES COMPLETENESS: Does the app-content / app-front-deployer module's `requires` block include ALL service instances the app binds to for credentials? (XSUAA, backend services, etc.)
3. XS-APP CONSISTENCY:
- Do static content routes have `"service": "app-front"`?
- Does the root `authenticationMethod` match the intended auth service?
- Is `authenticationType` consistent per route?
- (standalone-approuter source) Are ALL `"localDir"` entries removed? Any remaining `localDir` causes silent 404s.
4. AUTH FLOW: If switching to IAS, does xs-security.json need structural changes that were NOT addressed (missing oauth2-configuration, wrong xsappname format, etc.)?
5. KYMA COMPLETENESS (if Kyma target): Are ServiceInstance, ServiceBinding, APIRule, and Function/Deployment yaml all present and correctly referencing each other?
6. DESTINATION RESIDUE: Are there any remaining references to `sap.cloud.service`, `HTML5Runtime_enabled`, or html5-repo destination URL patterns that would break with app-front?
NOTE: `parameters.deploy_mode: html5-repo` at the MTA root level is REQUIRED for all appFront deployments — do NOT flag this as a residual artifact.
7. STANDALONE APPROUTER CONVERSION (standalone-approuter source only):
- Is the `approuter.nodejs` module completely removed from the migrated mta.yaml?
- Is `group: destinations` fully converted to `config.destinations` in the deployer module?
- Does the new HTML5 module (`type: html5`) have a valid build configuration (package.json with build:cf script, ui5.yaml)?
Return a table: Check | Result | Details
Then list any FAIL or WARN items as ACTION REQUIRED.
After the critic returns, address every FAIL and WARN before writing Phase 5. If the critic finds issues, go back and fix them, then re-run the critic.
Phase 5 — Post-Migration Report
5a — Persist the summary
Before presenting the report to the user, write it to disk:
mkdir -p .claude/appfront
Use the current timestamp as the filename (format YYYYMMDD-HHmmss):
date +"%Y%m%d-%H%M%S"
Write the full summary to .claude/appfront/<timestamp>-migration.md. The file must contain all sections below (Migration Summary table, build/deploy outcome, runtime URL if available, WorkZone steps, known issues).
Produce a final summary:
Migration Summary
| Before | After | |
|---|---|---|
| Deployment model | html5-apps-repo / Neo | appFront |
| Runtime | (original) | CF / Kyma |
| Auth service | (original) | XSUAA / IAS |
| Files modified | — | List |
| Files deleted | — | List |
| Files created | — | List |
Build & Deploy
Ask the user once:
Would you like to build and deploy the migrated project now?
⛔ If the user says yes, do not ask any further confirmation questions for the build and deploy steps — run mbt build, cf deploy, afctl login, and afctl list sequentially without additional prompts. The original project is never touched, so no additional confirmation is needed.
If yes, guide them through:
# 1. Build the MTA archive
mbt build
# 2. Deploy to CF
cf deploy <project-name>.mtar
After a successful deployment, use the appFront CLI to fetch the runtime URL:
Step 1 — Check if afctl is installed:
afctl --version 2>/dev/null || echo "NOT_INSTALLED"
If not installed, prompt the user:
npm install -g @sap/appfront-cli
Step 2 — Prerequisites: BTP role assignment
Before logging in, the user must be assigned the Application Frontend Developer role collection in the SAP BTP Cockpit. Remind the user:
Make sure you have been assigned the
Application Frontend Developerrole collection in BTP Cockpit. Without it, the login will succeed but operations will be rejected. If you are unsure, ask your BTP subaccount administrator.
Step 3 — Log in to appFront CLI:
First check if a session already exists:
afctl config 2>/dev/null
If the output shows a valid API endpoint and user, skip the login prompt and proceed to Step 4.
If no session exists, ask the user:
Please provide your appFront API endpoint URI. You can find it in the SAP BTP Cockpit by opening your subscribed Application Frontend application — it is displayed on the welcome page under "Application Frontend CLI", for example:
https://api.eu12.dt.appfront.cloud.sap/
Once the user provides the URI, log in using SSO (recommended — avoids typing credentials in the terminal):
afctl login -a <provided-uri> --sso
This opens a browser window for SSO authentication. After completing the browser login, the CLI session is established.
Step 4 — Fetch the runtime URL:
afctl list <app-name>
Present the runtime URL from the output to the user so they can open the application.
Cleanup (optional)
Ask the user:
Would you like to clean up the migrated deployment and remove all generated files?
If yes, ask a second confirmation:
Should service instances and service keys also be deleted? This will permanently remove all provisioned services (e.g. app-front, xsuaa). This cannot be undone.
-
If the user says no to deleting services:
cf undeploy <mta-id> -
If the user says yes to deleting services and keys:
cf undeploy <mta-id> --delete-services --delete-service-keys
After a successful undeploy, remove the migrated output folder:
rm -rf appfront-migrated/
⛔ Do NOT run the cleanup commands automatically. Only execute after both confirmations above are received from the user.
WorkZone Steps Required (if applicable) List any CDM/site assignment steps the user must complete manually.
Known Issues / Next Steps Any outstanding items flagged during migration that require user action.
Reference Files
| File | Description | Load When |
|---|---|---|
references/INDEX.md |
Full index of all reference files | Always, at start |
references/online-docs.md |
Curated SAP Help Portal URLs by migration phase | Always, at start — fetch live docs when local references are placeholders |
references/overview/appfront-architecture.md |
What appFront is and how it works | Phase 0, first time using this skill |
references/overview/appfront-vs-html5repo.md |
Side-by-side comparison table | Phase 1, when user asks "why migrate?" |
references/overview/migration-decision-tree.md |
Which migration path to take | Phase 0b, when source/target unclear |
references/source-types/html5-repo-app.md |
html5-repo source structure details | Phase 1, when source is html5-repo |
references/source-types/neo-html5-app.md |
Neo HTML5 app structure details | Phase 1, when source is Neo |
references/source-types/standalone-approuter.md |
Standalone approuter source: localDir routes, MTA group injection, CAP backend wiring | Phase 1, when source is standalone-approuter |
references/migration-guides/html5-repo-to-appfront.md |
Step-by-step html5-repo migration guide | Phase 1 and Phase 3, html5-repo source |
references/migration-guides/neo-to-appfront.md |
Step-by-step Neo migration guide | Phase 1 and Phase 3, Neo source |
references/migration-guides/standalone-approuter-to-appfront.md |
Step-by-step standalone approuter (localDir) migration guide | Phase 1 and Phase 3, standalone-approuter source |
references/migration-guides/managed-approuter-to-appfront.md |
WorkZone managed approuter variant | Phase 1, WorkZone source |
references/target-configs/cf-xsuaa-mta.yaml.md |
Canonical CF + XSUAA target mta.yaml | Phase 3, CF+XSUAA target |
references/target-configs/cf-ias-mta.yaml.md |
Canonical CF + IAS target mta.yaml | Phase 3, CF+IAS target |
references/target-configs/kyma-deployment.md |
Kyma deployment artifacts guide | Phase 3d, Kyma target |
references/target-configs/xs-app-patterns.md |
xs-app.json patterns per auth service | Phase 3b |
references/services/xsuaa-config.md |
xs-security.json patterns and scopes | Phase 3c, XSUAA auth |
references/services/ias-config.md |
IAS security config patterns | Phase 3c, IAS auth |
references/services/app-front-service.md |
appFront service plans and binding | Phase 3a, always |
references/services/destination-service.md |
When destination service is still needed | Phase 3a, if keeping backend destinations |
references/golden-path/golden-path-overview.md |
SAP Golden Path concept | Phase 0b, if backend is BTP |
references/golden-path/cap-backend-mta.yaml.md |
CAP + appFront full MTA example | Phase 3, CAP backend |
references/golden-path/fiori-elements-setup.md |
Fiori Elements manifest.json setup | Phase 3, Fiori Elements UI |
references/troubleshooting/known-issues.md |
Compatibility matrix and known blockers | Phase 4, if critic finds issues |
references/troubleshooting/workzone-integration.md |
CDM, site assignment, role collections | Phase 0c, if WorkZone detected |
references/troubleshooting/deployment-errors.md |
Common deploy failures post-migration | Phase 5, if deploy fails |
Known Migration Issues
| Issue | Source Type | Condition | Workaround |
|---|---|---|---|
| WorkZone CDM breaks after migration | html5-repo | sap.cloud.service present in source |
See references/troubleshooting/workzone-integration.md |
| 401 on all routes after migration | any | authenticationMethod or authenticationType mismatch in xs-app.json |
Verify xs-app.json against references/target-configs/xs-app-patterns.md |
| MTA build fails: unknown resource type | html5-repo | residual html5-apps-repo resource not removed |
Remove app-host resource and all requires references to it |
| 404 on all static content | standalone-approuter | "localDir" routes not converted to "service": "app-front" |
Replace all "localDir" entries with "service": "app-front" in xs-app.json |
| Backend 502 after migration | standalone-approuter | group: destinations not converted to config.destinations |
Add config.destinations block in deployer module with backend URL ~{srv-api/srv-url} |
mbt build fails: artifact not found |
standalone-approuter | HTML5 module missing package.json or build:cf script |
Add package.json with "build:cf": "ui5 build --dest dist" and ui5.yaml to app directory |
| Duplicate approuter CF app deployed | standalone-approuter | approuter.nodejs module left in migrated mta.yaml |
Remove the approuter.nodejs module entirely from migrated mta.yaml |
| Destination service created unnecessarily | any | BTP backend used config.destinations but destination service resource was also added | Remove destination service resource from mta.yaml — config.destinations is self-contained, no service instance needed |
| Build fails on Windows | Neo | build:cf script uses shell commands (cp, zip, mv) that are not available on Windows |
Use "build:cf": "ui5 build --dest dist" only — mbt handles the rest |
| App shows blank or broken UI after deploy | Neo | -dbg.js files present in controller folder; minified counterparts are incomplete |
Delete non-debug .js files and rename -dbg.js → .js before deploying (see 3a-neo-cleanup) |
manifest.json version validation error |
Neo | _version is too old (e.g. 1.1.0) for CF runtime |
Update _version to "1.65.0" in manifest.json |
| (populate from your team's experience) |