agentsclimarketplace

Sap cap advanced

Skill efeumutaslan/SAP-SKILLS/skills/sap-cap-advanced

23 SAP development skills for Claude Code — ABAP, RAP, CAP, Fiori, BTP, HANA, S/4HANA, Integration Suite and more. Agent Skills Specification compatible.

Install
npx -y skills add efeumutaslan/SAP-SKILLS --skill sap-cap-advanced

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

14.4 KB, as published. Nobody here has run it

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.yamlcf 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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.