L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Déploiement et opérations · SKILL.md

sap-cap-advanced

sap-cap-advanced

Advanced SAP CAP skill for enterprise patterns. Use when building multi-tenant CAP apps, deploying to Kyma, implementing XSUAA/IAS auth, advanced CDS modeling, or CAP remote services. If the user mentions CAP multitenancy, CAP Kyma deploy, mtxs, CAP extensibility, or advanced CDS aspects/compositions, use this skill.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: sap-cap-advanced description: > Advanced SAP CAP skill for enterprise patterns. Use when building multi-tenant CAP apps, deploying to Kyma, implementing XSUAA/IAS auth, advanced CDS modeling, or CAP remote services. If the user mentions CAP multitenancy, CAP Kyma deploy, mtxs, CAP extensibility, or advanced CDS aspects/compositions, use this skill. license: MIT metadata: author: SAP Skills Community version: "1.0.0" last_verified: "2026-03-24"

Advanced CAP — Multitenancy, Kyma & Enterprise Patterns

Related Skills

  • sap-hana-cloud — HANA Cloud as CAP persistence layer
  • sap-kyma-runtime — Deploying CAP on Kyma/Kubernetes
  • sap-security-authorization — XSUAA/IAS integration with CAP
  • sap-event-mesh — CAP messaging with Event Mesh

Quick Start

Advanced CAP project setup:

# Create CAP project with advanced features
cds init my-project --add hana,xsuaa,multitenancy,approuter,helm

# Add individual features
cds add hana           # HANA Cloud persistence
cds add xsuaa          # Authentication
cds add multitenancy   # SaaS multitenancy
cds add extensibility  # Tenant extensions
cds add helm           # Kyma/K8s deployment
cds add mtx            # MTX sidecar for tenant management
cds add messaging      # Event Mesh integration
cds add toggles        # Feature toggles

Core Concepts

CAP Multitenancy Architecture

                    ┌─────────────────────────┐
                    │    SaaS Application      │
                    │  (CAP + MTX Sidecar)     │
                    └──────────┬──────────────┘
                               │
              ┌────────────────┼────────────────┐
              ▼                ▼                 ▼
     ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
     │ HDI Tenant A │ │ HDI Tenant B │ │ HDI Tenant C │
     │ (Schema A)   │ │ (Schema B)   │ │ (Schema C)   │
     └──────────────┘ └──────────────┘ └──────────────┘
              │                │                 │
              └────────────────┼─────────────────┘
                               ▼
                    ┌──────────────────┐
                    │  HANA Cloud DB    │
                    └──────────────────┘

CAP Deployment Targets

TargetCommandArtifacts
Cloud Foundrycds build --for cfmta.yaml → cf deploy
Kyma/K8scds build --for kymaHelm chart → helm upgrade
Hybrid (local+cloud DB)cds bind + cds watchLocal app + remote HANA

CDS Advanced Modeling Features

FeatureUse Case
AspectsReusable field sets (managed, temporal, cuid)
CompositionsDocument structures (header→items)
AssociationsCross-entity navigation
ProjectionsService-level views (rename, exclude, redirect)
Temporal dataBitemporal tables (valid-from/to, system time)
Localized dataMulti-language texts (auto-generated _texts table)
ExtensibilityTenant-specific model extensions

Common Patterns

Pattern 1: Multitenancy Setup

// package.json — MTX configuration
{
  "cds": {
    "requires": {
      "multitenancy": true,
      "extensibility": true,
      "toggles": true,
      "[production]": {
        "db": { "kind": "hana", "deploy-format": "hdbtable" },
        "auth": { "kind": "xsuaa" }
      }
    },
    "mtx": {
      "element-prefix": ["Z_", "z_"],
      "namespace-blocklist": ["com.sap.", "sap."],
      "extension-allowlist": [
        { "for": ["my.bookshop.Books"], "new-fields": 5 },
        { "for": ["my.bookshop.Authors"], "new-fields": 3 }
      ]
    }
  }
}
// srv/tenant-provisioning.js — Custom tenant lifecycle
const cds = require('@sap/cds');

module.exports = class TenantProvisioning extends cds.ApplicationService {
  async init() {
    this.on('CREATE', 'tenant', async (req, next) => {
      const { subscribedTenantId, subscribedSubdomain } = req.data;
      console.log(`Provisioning tenant: ${subscribedTenantId}`);

      // Standard HDI container creation
      await next();

      // Custom post-provisioning (seed data, config)
      await this.seedTenantData(subscribedTenantId);
    });

    this.on('DELETE', 'tenant', async (req, next) => {
      const { subscribedTenantId } = req.data;
      console.log(`Deprovisioning tenant: ${subscribedTenantId}`);

      // Custom cleanup before HDI container deletion
      await this.archiveTenantData(subscribedTenantId);
      await next();
    });

    await super.init();
  }

  async seedTenantData(tenantId) {
    const db = await cds.connect.to('db');
    const { Configurations } = db.entities('my.app');
    await db.run(INSERT.into(Configurations).entries([
      { key: 'CURRENCY', value: 'EUR' },
      { key: 'LANGUAGE', value: 'EN' }
    ]));
  }
};

Pattern 2: CAP + Kyma Helm Deployment

# chart/values.yaml
global:
  domain: my-cluster.kyma.ondemand.com
  imagePullSecret:
    name: docker-registry-secret

srv:
  image:
    repository: my-registry.io/my-app-srv
    tag: latest
  bindings:
    db:
      serviceInstanceName: hana-hdi
    auth:
      serviceInstanceName: xsuaa-instance
  resources:
    limits:
      memory: 512Mi
      cpu: 500m
    requests:
      memory: 256Mi
      cpu: 100m

hana-deployer:
  image:
    repository: my-registry.io/my-app-hana-deployer
    tag: latest
  bindings:
    hana:
      serviceInstanceName: hana-hdi

html5-apps-deployer:
  image:
    repository: my-registry.io/my-app-html5-deployer
    tag: latest
# Build and deploy to Kyma
cds build --for kyma
docker build -t my-registry.io/my-app-srv:latest -f gen/srv/Dockerfile .
docker push my-registry.io/my-app-srv:latest
helm upgrade --install my-app ./chart \
  --namespace my-namespace \
  --set-file xsuaa.jsonParameters=xs-security.json

Pattern 3: Remote Service Integration (Mashup)

// srv/external/API_BUSINESS_PARTNER.cds (imported)
// cds import API_BUSINESS_PARTNER --from <edmx-url>

using { API_BUSINESS_PARTNER as bupa } from './external/API_BUSINESS_PARTNER';

// srv/mashup-service.cds — Combine local + remote
service MashupService {
  // Local entity
  entity Orders as projection on my.Orders {
    *, customer: redirected to Customers
  };

  // Remote entity (federated from S/4HANA)
  @readonly entity Customers as projection on bupa.A_BusinessPartner {
    key BusinessPartner as ID,
    BusinessPartnerFullName as name,
    to_BusinessPartnerAddress as addresses
  };
}
// srv/mashup-service.js — Remote service handler
const cds = require('@sap/cds');

module.exports = class MashupService extends cds.ApplicationService {
  async init() {
    const bupa = await cds.connect.to('API_BUSINESS_PARTNER');

    // Delegate reads to remote service
    this.on('READ', 'Customers', (req) => bupa.run(req.query));

    // Enrich local orders with remote customer data
    this.after('READ', 'Orders', async (orders) => {
      const customerIds = [...new Set(orders.map(o => o.customer_ID))];
      if (customerIds.length === 0) return;

      const customers = await bupa.run(
        SELECT.from('A_BusinessPartner')
          .where({ BusinessPartner: { in: customerIds } })
          .columns('BusinessPartner', 'BusinessPartnerFullName')
      );

      const customerMap = new Map(customers.map(c => [c.BusinessPartner, c]));
      for (const order of orders) {
        order.customerName = customerMap.get(order.customer_ID)?.BusinessPartnerFullName;
      }
    });

    await super.init();
  }
};

Pattern 4: Advanced Authorization

// srv/admin-service.cds
@requires: 'authenticated-user'
service AdminService {

  @restrict: [
    { grant: 'READ',   to: 'Viewer' },
    { grant: 'WRITE',  to: 'Editor' },
    { grant: '*',      to: 'Admin' }
  ]
  entity Products as projection on my.Products;

  // Instance-based auth (row-level)
  @restrict: [
    { grant: 'READ',  to: 'SalesRep', where: 'region = $user.region' },
    { grant: '*',     to: 'SalesManager' }
  ]
  entity SalesOrders as projection on my.SalesOrders;
}
// xs-security.json
{
  "xsappname": "my-app",
  "tenant-mode": "shared",
  "scopes": [
    { "name": "$XSAPPNAME.Viewer", "description": "Read access" },
    { "name": "$XSAPPNAME.Editor", "description": "Write access" },
    { "name": "$XSAPPNAME.Admin",  "description": "Full access" }
  ],
  "role-templates": [
    {
      "name": "Viewer",
      "scope-references": ["$XSAPPNAME.Viewer"],
      "attribute-references": [{ "name": "region" }]
    },
    {
      "name": "Editor",
      "scope-references": ["$XSAPPNAME.Viewer", "$XSAPPNAME.Editor"],
      "attribute-references": [{ "name": "region" }]
    },
    {
      "name": "Admin",
      "scope-references": ["$XSAPPNAME.Admin"]
    }
  ]
}

Pattern 5: CAP with HANA Native Artifacts

// db/schema.cds — Use HANA-specific features
using { managed, cuid } from '@sap/cds/common';

@cds.persistence.journal  // Enable temporal tables
entity AuditLog : cuid, managed {
  action    : String(50);
  entity    : String(100);
  oldValue  : LargeString;
  newValue  : LargeString;
}

// Use HANA calculation view
@cds.persistence.exists  // Don't generate table, it exists in HANA
entity SalesDashboard {
  key region    : String(10);
  totalRevenue  : Decimal(15,2);
  orderCount    : Integer;
  avgOrderValue : Decimal(15,2);
}
// db/src/CV_SALES_DASHBOARD.hdbcalculationview
// (Graphical calculation view created in BAS)
// Referenced by @cds.persistence.exists entity above
-- db/src/SP_COMPLEX_CALC.hdbprocedure
PROCEDURE "SP_COMPLEX_CALC" (
  IN iv_year INTEGER,
  OUT et_result TABLE (region NVARCHAR(10), revenue DECIMAL(15,2))
)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA
AS
BEGIN
  et_result = SELECT region, SUM(amount) AS revenue
              FROM "MY_APP_ORDERS"
              WHERE YEAR("createdAt") = :iv_year
              GROUP BY region;
END;

Pattern 6: CAP Feature Toggles

// srv/feature-service.js
const cds = require('@sap/cds');
const toggles = require('@sap/cds-mtx/toggles');

module.exports = class FeatureService extends cds.ApplicationService {
  async init() {
    this.before('CREATE', 'Orders', async (req) => {
      // Check if new pricing engine is enabled for this tenant
      if (await toggles.isEnabled('new-pricing-engine', req.tenant)) {
        req.data.price = await this.calculateNewPrice(req.data);
      } else {
        req.data.price = await this.calculateLegacyPrice(req.data);
      }
    });

    await super.init();
  }
};

Error Catalog

ErrorMessageRoot CauseFix
TENANT_NOT_FOUNDNo HDI container for tenantTenant not provisionedRun tenant subscription; check MTX sidecar logs
CDS_COMPILE_ERRORModel compilation failedInvalid CDS syntax or circular dependencyRun cds compile --to sql locally to debug
XSUAA: ForbiddenJWT scope mismatchMissing role assignmentAssign role collection to user in BTP cockpit
Remote service: 401Destination auth failedExpired OAuth token or wrong destination configCheck BTP destination; regenerate credentials
HDI deploy: 409Container already existsDuplicate tenant provisioningCheck MTX sidecar idempotency; clean up orphans
Helm: ImagePullBackOffCannot pull container imageWrong registry or missing secretVerify image exists; check imagePullSecret
cds bind: Service not foundBinding resolution failedService key missing or wrong nameRun cf service-key <instance> <key> to verify
HANA: Column store errorSchema deployment failedIncompatible schema evolutionCheck .hdbmigrationtable for migration steps

Performance Tips

  1. Batch remote calls — Use $batch for multiple remote service requests; CAP auto-batches with cds.ql
  2. Projection pushdown — Use columns() in queries; CAP pushes column selection to HANA
  3. Expand wisely — $expand with deep nesting causes N+1; prefer flat queries with client-side assembly
  4. Connection pooling — CAP pools HANA connections by default; tune pool.max for high-concurrency
  5. MTX sidecar — Deploy MTX as separate microservice for tenant operations (don't block main app)
  6. Streaming — Use $top/$skip pagination for large result sets; CAP supports @odata.maxpagesize
  7. HANA artifacts — For complex analytics, use calculation views (@cds.persistence.exists) over CDS views

Validation Workflow

Before deploying a CAP project, validate structure and configuration:

bash scripts/validate-cap-project.sh .

Deploy checklist:

  • CDS models compile (cds build)
  • Tests pass (npm test)
  • Auth annotations present on all services
  • mta.yaml or Helm chart configured for target platform
  • No hardcoded credentials in code

Gotchas

  • MTX sidecar version: Must match @sap/cds version exactly; mismatch causes tenant operations to fail
  • Kyma vs CF bindings: Kyma uses service bindings as Kubernetes secrets; CF uses VCAP_SERVICES
  • Remote service quotas: BTP destination connections have concurrency limits; implement circuit breaker
  • Schema evolution: HDI doesn't support all schema changes (e.g., narrowing column types); plan migrations
  • cds build output: --for cf generates mta.yaml; --for kyma generates Helm chart — different structures
  • Feature toggles: Require @sap/cds-mtx package and MTX sidecar; not available in single-tenant mode

MCP Server Integration

For AI-assisted CAP development, add to your .mcp.json:

{
  "mcpServers": {
    "cap-mcp": {
      "command": "npx", "args": ["-y", "@cap-js/mcp-server"]
    },
    "fiori-mcp": {
      "command": "npx", "args": ["-y", "@sap-ux/fiori-mcp-server"]
    }
  }
}
  • CAP MCP (official): CDS model search + CAP documentation search
  • Fiori MCP (official): Fiori elements app generation, annotation editing
Skills enregistrées