SAP CAP Node.js Development Skill
1. Scope guardrails (read first, every time)
Before doing anything, classify the request:
- CAP Node.js development? → proceed.
- UI / frontend work? → refuse: "This skill is SAP CAP Node.js only. UI/frontend
implementation (Fiori custom code, UI5, React, Vue, plain HTML/CSS/JS) is out of scope.
CAP-side UI annotations in
.cds are in scope; the UI app itself is not."
- Backend in another language or stack? → refuse: "This skill is SAP CAP Node.js only.
Java CAP, Spring, plain Node/Express, NestJS, Python, Go, .NET, and non-CAP microservices
are out of scope."
- Non-CAP architecture (custom OData/REST/GraphQL outside CAP)? → refuse with the same
message. CAP must be the framework (
@sap/cds + cds.ApplicationService, or documented
@cap-js/* plugins).
- Uses a private / protected / deprecated API? → refuse and propose the documented public
alternative. If none exists, say so and stop.
When in doubt, ask the user to confirm the request fits the CAP Node.js scope before writing code.
2. Public-API rule
- Only import from documented, stable entry points:
@sap/cds, @sap/cds/common,
@cap-js/sqlite, @cap-js/hana, @cap-js/postgres, @cap-js/attachments,
@cap-js/audit-logging, @cap-js/change-tracking, @cap-js/telemetry, @cap-js/graphql,
@cap-js/mcp-server, @sap/cds-mtxs.
- Never reach into
@sap/cds/lib/*, node_modules/@sap/cds/lib/*, or any path the docs do not
describe.
- Never use methods/options that the changelog flags as deprecated or removed.
- Never rely on undocumented behavior of a documented API ("it happens to work today").
- If the public surface cannot do what the user wants, say so — do not fall back to internals.
3. Domain-first / Less code → Less mistakes
"Every line of code not written is free of errors." — SAP Capire
https://cap.cloud.sap/docs/get-started/features#less-code-%E2%86%92-less-mistakes
CAP captures domain knowledge and intent declaratively ("What, not How"). This skill
follows that principle: prefer the CDS model, annotations, projections, and CAP's generic
providers over hand-written handlers and SQL.
CAP's generic providers already handle: CRUD, nested documents, drafts, media, search,
pagination, sorting, authentication / authorization, localization, input validation,
auto-generated keys, concurrency control. Do not re-implement these in code.
Decision order when adding a new behavior — only drop to the next step if the previous one
cannot express it:
- Schema — types, associations, compositions, aspects from
@sap/cds/common.
- Annotations —
@mandatory, @assert.*, @readonly, @insertonly, @requires,
@restrict, @cds.persistence.*, @cds.search, @odata.draft.enabled, @odata.etag,
@UI.*.
- Views / projections — expose subsets, filter rows, compute fields, join entities in CDS.
- Status Flows — when the behavior is a state machine (row walks through named states),
use
@flow.status + @from + @to. CAP validates the entry state and writes the target
state. See references/status-flow.md. ⚠ Currently Gamma in
capire — only adopt with explicit team acceptance.
- CAP plugins —
@cap-js/attachments, @cap-js/audit-logging, @cap-js/change-tracking,
@cap-js/telemetry, @cap-js/graphql, etc.
- Concurrency control —
@odata.etag (via managed.modifiedAt) for optimistic locking;
cds.tx(req) with .forUpdate() on the base entity when invariants span multiple rows.
See references/concurrency-control.md and
references/race-conditions.md.
- Event handlers (last resort) — only for behavior that is genuinely business logic and
cannot be expressed declaratively by steps 1–6. Never re-implement what
@from/@to,
@odata.etag, @assert.*, @requires, or a projection already does for free.
Full explanation, examples, and the "is this PR domain-first?" checklist:
references/domain-first.md.
4. Where to put what
| Concern |
Where it lives |
| Keys, types, relationships |
db/schema.cds |
| Required / range / format / unique |
CDS @mandatory, @assert.* |
| Computed fields |
CDS calculated elements (= expr, stored) |
| Exposed subset / filtered rows |
srv/*.cds projection |
| Joins across entities |
CDS view (as select from … join …) |
| Authorization (who can do what) |
@requires, @restrict |
| Fiori UI shape |
@UI.*, @Common.* annotations in CDS |
| i18n texts |
_i18n/ .properties files |
| Seed / reference data |
CSV in db/data/ |
| Cross-cutting concerns |
@cap-js/* plugin (configured, not coded) |
| Genuine business logic |
Node.js event handler in srv/*.js |
The app/ folder (UI applications) is out of scope for this skill.
5. Project structure
project/
├── app/ # UI content ← out of scope
├── srv/ # Service definitions (.cds, .js/.ts) ← in scope
├── db/ # Data models, views, seed data ← in scope
│ ├── schema.cds
│ └── data/
├── package.json # Dependencies + CDS config ← in scope
└── .cdsrc.json # CDS configuration (optional)
6. Quick start (minimal)
npm i -g @sap/cds-dk @sap/cds-lsp
cds init <project-name>
cds watch
Add capabilities as needed (cds add hana | sqlite | xsuaa | mta | multitenancy | typescript).
Full CLI reference: references/cli-complete.md and
references/tools-complete.md.
Domain-first starter — model first, expose with a projection, no handler needed:
// db/schema.cds
using { cuid, managed } from '@sap/cds/common';
namespace my.bookshop;
entity Books : cuid, managed {
title : String(111) @mandatory;
stock : Integer @assert.range: [0, 99999];
price : Decimal(9,2);
}
// srv/catalog-service.cds
using { my.bookshop as my } from '../db/schema';
@requires: 'authenticated-user'
service CatalogService {
@readonly entity Books as projection on my.Books where stock > 0;
}
That's a working, validated, authorized, searchable OData service — zero JS.
For more entity / projection / view / annotation patterns, see the templates folder and the
references below.
7. MCP integration
The skill integrates with the official CAP MCP server, giving the agent live access to the
project's compiled CSN model and CAP docs:
search_model — fuzzy search entities, services, actions, and relationships in the CSN.
search_docs — semantic search through CAP documentation.
Setup: references/mcp-integration.md.
Use cases: references/mcp-use-cases.md.
8. Bundled resources (index)
Philosophy & rules
- domain-first.md — "Less code → less mistakes", decision order,
annotations and views to prefer over code, anti-patterns.
- best-practices.md — full DO / DON'T, code smells, review
checklist.
- security-audit.md — audit matrix against the AI-agent /
supply-chain attack surface (prompt injection, MCP poisoning, supply chain, eval,
SSRF, credential leakage, etc.) and the standing rules the skill enforces on agent output.
Language & query
- cdl-syntax.md — CDL syntax reference.
- annotations-reference.md — annotations catalog.
- cql-queries.md — CQL basics.
- cql-patterns.md — CQL usage patterns.
- csn-cqn-cxn.md — Core Schema Notation and query APIs.
- sql-injection.md — why CAP's CQL prevents injection, when raw
SQL is allowed, identifier allow-lists.
State, concurrency & safety
- status-flow.md —
@flow.status + @from + @to for
state-machine use cases (capire Gamma).
- concurrency-control.md —
@odata.etag optimistic
locking, .forUpdate() pessimistic locking, draft serialization.
- race-conditions.md — TOCTOU, transactions, bootstrap
races, event-consumer idempotency.
Runtime & handlers (use sparingly — model first)
- nodejs-runtime.md — Node.js runtime reference.
- event-handlers-nodejs.md — handler patterns.
- event-handlers-patterns.md — extended patterns.
- service-definitions.md — service definition patterns.
Persistence
- databases.md — DB configuration.
- data-privacy-security.md — GDPR, security.
- localization-temporal.md — i18n (UI bundle
i18n.properties and error-message bundle messages.properties for req.error / req.reject, built-in keys ASSERT_MANDATORY, ASSERT_RANGE, ASSERT_FORMAT, ASSERT_TARGET, MULTIPLE_ERRORS), temporal data.
Integration & deployment
- consuming-services-deployment.md — remote
services, bindings, deployment.
- deployment-cf.md — Cloud Foundry deployment details.
- extensibility-multitenancy.md — SaaS / MTX.
- plugins-reference.md —
@cap-js/* plugins.
- fiori-integration.md — CAP-side UI annotations only.
Tooling
- cli-complete.md —
cds CLI reference.
- tools-complete.md — full tooling overview.
- mcp-integration.md — CAP MCP server.
- mcp-use-cases.md — MCP scenarios.
- CAP_Troubleshooting.md — troubleshooting.
Templates
- templates/bookshop-schema.cds — data model example.
- templates/catalog-service.cds — service definition.
- templates/fiori-annotations.cds — UI annotations (CDS only).
- templates/mta.yaml — MTA descriptor.
- templates/package.json — project config.
- templates/service-handler.js — Node.js handler (use sparingly).
- templates/service-handler.ts — TypeScript handler.
- templates/xs-security.json — XSUAA security config.
9. Quick links
10. Version
- Skill Version: 3.1.0
- Runtime: Node.js only
- CAP Version: @sap/cds 9.7.x
- MCP Version: @cap-js/mcp-server 0.0.3+
- LSP Version: @sap/cds-lsp 9.7.x
- Last Verified: 2026-05-12
- License: GPL-3.0
1---2name: sap-cap-nodejs-dev3description: SAP Cloud Application Programming Model (CAP) development skill for the **Node.js runtime only**. Domain-first: prefers CDS schema, annotations, projections, and CAP's generic providers over hand-written handler code ("less code → less mistakes"). Use when the user asks to: build CAP applications, define CDS models, design entities / associations / views / projections, add annotations (validation, authorization, UI, search, drafts), configure databases (SQLite / HANA / PostgreSQL through CAP), deploy to SAP BTP (Cloud Foundry or Kyma), wire multitenancy / messaging, or add CAP plugins. Strict scope — this skill ONLY develops SAP CAP Node.js. It MUST refuse, and tell the user why, whenever a request is: - Frontend / UI implementation (Fiori Elements custom code, UI5 controls, React, Vue, HTML/CSS/JS UI work, any browser-side code). CAP-side `@UI.*` annotations in `.cds` are in scope; writing the UI itself is not. - Backend in any other language or stack (Java CAP, Spring, plain Node/Express, NestJS, Python, Go4license: GPL-3.05---67# SAP CAP Node.js Development Skill89## 1. Scope guardrails (read first, every time)1011Before doing anything, classify the request:12131. **CAP Node.js development?** → proceed.142. **UI / frontend work?** → refuse: "This skill is SAP CAP Node.js only. UI/frontend15 implementation (Fiori custom code, UI5, React, Vue, plain HTML/CSS/JS) is out of scope.16 CAP-side UI *annotations* in `.cds` are in scope; the UI app itself is not."173. **Backend in another language or stack?** → refuse: "This skill is SAP CAP Node.js only.18 Java CAP, Spring, plain Node/Express, NestJS, Python, Go, .NET, and non-CAP microservices19 are out of scope."204. **Non-CAP architecture (custom OData/REST/GraphQL outside CAP)?** → refuse with the same21 message. CAP must be the framework (`@sap/cds` + `cds.ApplicationService`, or documented22 `@cap-js/*` plugins).235. **Uses a private / protected / deprecated API?** → refuse and propose the documented public24 alternative. If none exists, say so and stop.2526When in doubt, ask the user to confirm the request fits the CAP Node.js scope before writing code.2728## 2. Public-API rule2930- Only import from documented, stable entry points: `@sap/cds`, `@sap/cds/common`,31 `@cap-js/sqlite`, `@cap-js/hana`, `@cap-js/postgres`, `@cap-js/attachments`,32 `@cap-js/audit-logging`, `@cap-js/change-tracking`, `@cap-js/telemetry`, `@cap-js/graphql`,33 `@cap-js/mcp-server`, `@sap/cds-mtxs`.34- Never reach into `@sap/cds/lib/*`, `node_modules/@sap/cds/lib/*`, or any path the docs do not35 describe.36- Never use methods/options that the changelog flags as **deprecated** or **removed**.37- Never rely on undocumented behavior of a documented API ("it happens to work today").38- If the public surface cannot do what the user wants, say so — do not fall back to internals.3940## 3. Domain-first / Less code → Less mistakes4142> "Every line of code not written is free of errors." — SAP Capire43> https://cap.cloud.sap/docs/get-started/features#less-code-%E2%86%92-less-mistakes4445CAP captures **domain knowledge and intent declaratively** ("What, not How"). This skill46follows that principle: prefer the CDS model, annotations, projections, and CAP's generic47providers over hand-written handlers and SQL.4849**CAP's generic providers already handle**: CRUD, nested documents, drafts, media, search,50pagination, sorting, authentication / authorization, localization, input validation,51auto-generated keys, concurrency control. **Do not re-implement these in code.**5253**Decision order** when adding a new behavior — only drop to the next step if the previous one54cannot express it:55561. **Schema** — types, associations, compositions, aspects from `@sap/cds/common`.572. **Annotations** — `@mandatory`, `@assert.*`, `@readonly`, `@insertonly`, `@requires`,58 `@restrict`, `@cds.persistence.*`, `@cds.search`, `@odata.draft.enabled`, `@odata.etag`,59 `@UI.*`.603. **Views / projections** — expose subsets, filter rows, compute fields, join entities in CDS.614. **Status Flows** — when the behavior is a state machine (row walks through named states),62 use `@flow.status` + `@from` + `@to`. CAP validates the entry state and writes the target63 state. See [references/status-flow.md](references/status-flow.md). ⚠ Currently Gamma in64 capire — only adopt with explicit team acceptance.655. **CAP plugins** — `@cap-js/attachments`, `@cap-js/audit-logging`, `@cap-js/change-tracking`,66 `@cap-js/telemetry`, `@cap-js/graphql`, etc.676. **Concurrency control** — `@odata.etag` (via `managed.modifiedAt`) for optimistic locking;68 `cds.tx(req)` with `.forUpdate()` on the base entity when invariants span multiple rows.69 See [references/concurrency-control.md](references/concurrency-control.md) and70 [references/race-conditions.md](references/race-conditions.md).717. **Event handlers** (last resort) — only for behavior that is genuinely business logic and72 cannot be expressed declaratively by steps 1–6. Never re-implement what `@from`/`@to`,73 `@odata.etag`, `@assert.*`, `@requires`, or a projection already does for free.7475Full explanation, examples, and the "is this PR domain-first?" checklist:76[references/domain-first.md](references/domain-first.md).7778## 4. Where to put what7980| Concern | Where it lives |81|--------------------------------------|--------------------------------------------------|82| Keys, types, relationships | `db/schema.cds` |83| Required / range / format / unique | CDS `@mandatory`, `@assert.*` |84| Computed fields | CDS calculated elements (`= expr`, `stored`) |85| Exposed subset / filtered rows | `srv/*.cds` projection |86| Joins across entities | CDS view (`as select from … join …`) |87| Authorization (who can do what) | `@requires`, `@restrict` |88| Fiori UI shape | `@UI.*`, `@Common.*` annotations in CDS |89| i18n texts | `_i18n/` `.properties` files |90| Seed / reference data | CSV in `db/data/` |91| Cross-cutting concerns | `@cap-js/*` plugin (configured, not coded) |92| Genuine business logic | Node.js event handler in `srv/*.js` |9394The `app/` folder (UI applications) is **out of scope** for this skill.9596## 5. Project structure9798```99project/100├── app/ # UI content ← out of scope101├── srv/ # Service definitions (.cds, .js/.ts) ← in scope102├── db/ # Data models, views, seed data ← in scope103│ ├── schema.cds104│ └── data/105├── package.json # Dependencies + CDS config ← in scope106└── .cdsrc.json # CDS configuration (optional)107```108109## 6. Quick start (minimal)110111```sh112npm i -g @sap/cds-dk @sap/cds-lsp113cds init <project-name>114cds watch115```116117Add capabilities as needed (`cds add hana | sqlite | xsuaa | mta | multitenancy | typescript`).118Full CLI reference: [references/cli-complete.md](references/cli-complete.md) and119[references/tools-complete.md](references/tools-complete.md).120121**Domain-first starter** — model first, expose with a projection, no handler needed:122123```cds124// db/schema.cds125using { cuid, managed } from '@sap/cds/common';126namespace my.bookshop;127128entity Books : cuid, managed {129 title : String(111) @mandatory;130 stock : Integer @assert.range: [0, 99999];131 price : Decimal(9,2);132}133```134135```cds136// srv/catalog-service.cds137using { my.bookshop as my } from '../db/schema';138139@requires: 'authenticated-user'140service CatalogService {141 @readonly entity Books as projection on my.Books where stock > 0;142}143```144145That's a working, validated, authorized, searchable OData service — zero JS.146147For more entity / projection / view / annotation patterns, see the templates folder and the148references below.149150## 7. MCP integration151152The skill integrates with the official CAP MCP server, giving the agent live access to the153project's compiled CSN model and CAP docs:154155- `search_model` — fuzzy search entities, services, actions, and relationships in the CSN.156- `search_docs` — semantic search through CAP documentation.157158Setup: [references/mcp-integration.md](references/mcp-integration.md).159Use cases: [references/mcp-use-cases.md](references/mcp-use-cases.md).160161## 8. Bundled resources (index)162163### Philosophy & rules164- [domain-first.md](references/domain-first.md) — "Less code → less mistakes", decision order,165 annotations and views to prefer over code, anti-patterns.166- [best-practices.md](references/best-practices.md) — full DO / DON'T, code smells, review167 checklist.168- [security-audit.md](references/security-audit.md) — audit matrix against the AI-agent /169 supply-chain attack surface (prompt injection, MCP poisoning, supply chain, eval,170 SSRF, credential leakage, etc.) and the standing rules the skill enforces on agent output.171172### Language & query173- [cdl-syntax.md](references/cdl-syntax.md) — CDL syntax reference.174- [annotations-reference.md](references/annotations-reference.md) — annotations catalog.175- [cql-queries.md](references/cql-queries.md) — CQL basics.176- [cql-patterns.md](references/cql-patterns.md) — CQL usage patterns.177- [csn-cqn-cxn.md](references/csn-cqn-cxn.md) — Core Schema Notation and query APIs.178- [sql-injection.md](references/sql-injection.md) — why CAP's CQL prevents injection, when raw179 SQL is allowed, identifier allow-lists.180181### State, concurrency & safety182- [status-flow.md](references/status-flow.md) — `@flow.status` + `@from` + `@to` for183 state-machine use cases (capire Gamma).184- [concurrency-control.md](references/concurrency-control.md) — `@odata.etag` optimistic185 locking, `.forUpdate()` pessimistic locking, draft serialization.186- [race-conditions.md](references/race-conditions.md) — TOCTOU, transactions, bootstrap187 races, event-consumer idempotency.188189### Runtime & handlers (use sparingly — model first)190- [nodejs-runtime.md](references/nodejs-runtime.md) — Node.js runtime reference.191- [event-handlers-nodejs.md](references/event-handlers-nodejs.md) — handler patterns.192- [event-handlers-patterns.md](references/event-handlers-patterns.md) — extended patterns.193- [service-definitions.md](references/service-definitions.md) — service definition patterns.194195### Persistence196- [databases.md](references/databases.md) — DB configuration.197- [data-privacy-security.md](references/data-privacy-security.md) — GDPR, security.198- [localization-temporal.md](references/localization-temporal.md) — i18n (UI bundle `i18n.properties` and **error-message bundle `messages.properties`** for `req.error` / `req.reject`, built-in keys `ASSERT_MANDATORY`, `ASSERT_RANGE`, `ASSERT_FORMAT`, `ASSERT_TARGET`, `MULTIPLE_ERRORS`), temporal data.199200### Integration & deployment201- [consuming-services-deployment.md](references/consuming-services-deployment.md) — remote202 services, bindings, deployment.203- [deployment-cf.md](references/deployment-cf.md) — Cloud Foundry deployment details.204- [extensibility-multitenancy.md](references/extensibility-multitenancy.md) — SaaS / MTX.205- [plugins-reference.md](references/plugins-reference.md) — `@cap-js/*` plugins.206- [fiori-integration.md](references/fiori-integration.md) — CAP-side UI annotations only.207208### Tooling209- [cli-complete.md](references/cli-complete.md) — `cds` CLI reference.210- [tools-complete.md](references/tools-complete.md) — full tooling overview.211- [mcp-integration.md](references/mcp-integration.md) — CAP MCP server.212- [mcp-use-cases.md](references/mcp-use-cases.md) — MCP scenarios.213- [CAP_Troubleshooting.md](references/CAP_Troubleshooting.md) — troubleshooting.214215### Templates216- [templates/bookshop-schema.cds](templates/bookshop-schema.cds) — data model example.217- [templates/catalog-service.cds](templates/catalog-service.cds) — service definition.218- [templates/fiori-annotations.cds](templates/fiori-annotations.cds) — UI annotations (CDS only).219- [templates/mta.yaml](templates/mta.yaml) — MTA descriptor.220- [templates/package.json](templates/package.json) — project config.221- [templates/service-handler.js](templates/service-handler.js) — Node.js handler (use sparingly).222- [templates/service-handler.ts](templates/service-handler.ts) — TypeScript handler.223- [templates/xs-security.json](templates/xs-security.json) — XSUAA security config.224225## 9. Quick links226227- CAP Documentation: https://cap.cloud.sap/docs/228- CDS Language: https://cap.cloud.sap/docs/cds/229- Node.js Runtime: https://cap.cloud.sap/docs/node.js/230- Best Practices (official): https://cap.cloud.sap/docs/about/best-practices231- GitHub: https://github.com/cap-js/docs232233## 10. Version234235- Skill Version: 3.1.0236- Runtime: Node.js only237- CAP Version: @sap/cds 9.7.x238- MCP Version: @cap-js/mcp-server 0.0.3+239- LSP Version: @sap/cds-lsp 9.7.x240- Last Verified: 2026-05-12241- License: GPL-3.0