Use for SAP CAP (Cloud Application Programming Model) Node.js development, code review, and hardening. Activate when writing or reviewing CDS models, service handlers, @requires/@restrict authorization, cds.ql queries, HANA deployment, CAP testing with cds.test, AI integration via SAP Cloud SDK, or any question about @sap/cds, CDS modeling, OData, AsyncAPI, MCP routing, multitenancy, or CAP-specific Node.js patterns.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Use for SAP CAP (Cloud Application Programming Model) Node.js development, code review, and hardening. Activate when writing or reviewing CDS models, service handlers, @requires/@restrict authorization, cds.ql queries, HANA deployment, CAP testing with cds.test, AI integration via SAP Cloud SDK, or any question about @sap/cds, CDS modeling, OData, AsyncAPI, MCP routing, multitenancy, or CAP-specific Node.js patterns.
when_to_use
Trigger on: CDS entity/service definitions, service handlers (before/on/after), cds.ql SELECT/INSERT/UPDATE/DELETE, @requires/@restrict annotations, cds.test suites, mta.yaml, xs-security.json, cds compile/build/deploy errors, HANA vector search, SAP AI SDK in handlers, draft/Fiori entities, schema evolution, cds bind, CAP multitenancy (MTX).
ai-integration.md — Cloud SDK for AI (Orchestration) in handlers, async cds.spawn, HANA Vector RAG, prompt externalization, sizing
Version & Evidence Tracking
Field
Value
Author
Kallol Chakraborty
Skill version
1.1.0
CAP version
@sap/cds ^9.7.x (Node.js runtime only)
Docs source
Official SAP CAP Documentation (~54k lines across 246 topics)
Last verified
2026-08-04
Verification method
Baseline subagent test + 3 pressure scenarios + rationalization resistance test + automated eval suite
Evaluation score
100% — all gates pass, all 11 rationalizations blocked
Originality
100% original prose & examples; no text copied from other skills
Evidence ledger
See §10. Evidence Ledger in this document for per-rule verification sources
Related Skills
Skill
Reach for it when...
sap-fiori-tools
Generating Fiori Elements apps & UI annotations
sapui5
Custom UI5 apps & advanced UI patterns
sap-btp-developer-guide
End-to-end BTP development
sap-cloud-sdk-ai
SDK-level AI calls in CAP handlers
Behavioral Guardrails — READ FIRST
Violating the letter of these rules IS violating the spirit of these rules.
This skill enforces CAP-specific discipline. Agents under pressure (time, sunk cost, authority, exhaustion) will rationalize skipping CAP rules. Every rationalization below has been observed in baseline testing and is explicitly forbidden.
Red Flags — STOP and Start Over
If you catch yourself thinking or doing ANY of these, delete the code and restart with the skill:
"This service is internal, it doesn't need @requires" → Wrong. Default is NO access control.
"I'll add authorization later" → Wrong. Auth is Gate 1 — zero tolerance.
"@readonly is enough for PII" → Wrong. @readonly blocks writes, allows reads for ALL.
"if (!rows) works for my test data" → Wrong. Empty array is truthy — dead code in production.
"Decimal math in JS is fine for small numbers" → Wrong. Decimal/Int64 are ALWAYS strings; precision loss is guaranteed.
"I'll catch the error and return a nice message" → Wrong. Swallowing errors → HTTP 200 hides failures.
"This before handler just does a quick SELECT" → Wrong. before = sync validation only; DB I/O in on.
"Custom READ doesn't need $count support" → Wrong. Breaks filter/paging/expand — data exposure + perf trap.
"Tests pass without mock auth" → Wrong. Unmocked auth = false positives; 401/403 never tested.
"I'm following the spirit, not the ritual" → Wrong. Violating the letter IS violating the spirit.
All of these mean: Delete code. Restart with the skill.
Rationalization Table — Excuse vs Reality
Excuse
Reality
"Service is internal / dev only"
Internal services still need @protocol: 'none' AND auth; dev data leaks to prod
"I'll add @restrict in a follow-up PR"
Follow-ups slip; auth gaps compound. One line: @requires: 'authenticated-user'
"@readonly protects reads"
@readonly = @restrict: [{grant:'READ'}] — allows ALL authenticated users
"My test data has rows, so if (!rows) works"
Empty array is truthy in JS; production WILL hit empty results
"Decimal precision loss is negligible"
Financial/regulatory data — precision loss = compliance violation
"Swallowing errors makes UX smoother"
HTTP 200 on failure = silent data corruption, no monitoring alert
"Exact pins prevent dependency drift"
package-lock.json freezes for deploy; exact pins break model reuse & dedupe
"This DB read in before is harmless"
before listeners run in PARALLEL; race conditions, tx contamination
"Custom READ is simpler without req.query"
Bypasses $filter/$top/$skip/$expand/$count — N+1, data leaks, broken clients
"Tests are green without negative cases"
Green tests without 401/403/404 = auth never exercised = false confidence
"I'm following the spirit, not the ritual"
Violating the letter IS violating the spirit — there are no exceptions
Explicit Prohibitions — No Exceptions
Do not do these. No "unless", no "but", no "spirit over letter".
❌ Never expose a service/entity/action without @requires or @restrict
❌ Never use @readonly as the only protection for sensitive data
❌ Never write if (!rows) on SELECT.from(...) result — use SELECT.one / .first()
❌ Never do arithmetic on Decimal/Int64 in JavaScript — use DB-side set/with
❌ Never catch an error and return HTTP 200 — augment & re-throw the SAME error object
❌ Never exact-pin @sap/cds or framework deps — use caret ranges ^9.1.0
❌ Never do DB I/O in before handlers — validation only, synchronous
❌ Never write custom on READ that ignores req.query
❌ Never use new Date() / Date.now() for managed timestamps — use req.timestamp
❌ Never put @sap/cds-dk or test frameworks in dependencies — devDependencies only
❌ Never commit without package-lock.json and engines: { node: ">=18" }
❌ Never claim "done" without cds compile PASS + cds test PASS
Common Issues — First Check
When something goes wrong, check these in order before digging deeper:
Symptom
First check
cds watch / cds serve won't start
Confirm @sap/cds-dk is installed, Node ≥ 18, and package.json scripts are correct
Entity or service can't be found
If CAP MCP is configured, run search_model; otherwise open the db/ and srv/ CDS sources and trace the definitions
HANA deployment errors
Confirm the HDI service binding is in place, the mta.yaml is well-formed, and HANA-specific deploy settings are present
Auth behavior seems off
Walk the @requires/@restrict declarations, identity-provider bindings, and role assignments on users
SELECT.from(...) returns an empty array
A where clause may have filtered everything — empty is a valid result, not a bug
Decimal/Int64 arrive as strings
Expected: these types are strings in JS; do arithmetic DB-side
req.query undefined in a custom handler
Handler must be registered on a served service, not a standalone script
cds.test() fails on env mismatch
Call cds.test() before importing other cds APIs; set CDS_TEST_ENV_CHECK=y
package-lock.json missing from git
Generate with npm install, then commit — exact pins break model reuse
@sap/cds-dk not in devDependencies
cds CLI commands fail in CI; relocate it to devDependencies
MCP & LSP Routing
This skill cooperates with the CAP MCP server and CAP LSP so answers stay tied to the
live project rather than generic theory.
MCP Tools
Tool
What it gives you
search_model
Fuzzy matching over the compiled CSN: entities, services, actions, and their relations
search_docs
Semantic lookup into CAP docs for how-to, syntax, and pattern questions
Setup: Add @cap-js/mcp-server as a devDependency and wire it per your client's
MCP guide. Pin and vet the server package through sap-dependency-security and run
its validate:mcp-security check before committing.
LSP Integration
@sap/cds-lsp gives live CDS validation, completions, and diagnostics in the editor.
Configure it via .lsp.json or your client's LSP settings. With no LSP available, fall
back to this skill's Markdown guidance, its bundled references, rg, and the CAP CLI.
Routing Priority
MCP first for model and docs questions (live, project-aware)
LSP for real-time editing feedback
This skill for code review, development rules, and behavioral guardrails
Direct file search (rg -n "<entity|service|aspect|annotation|handler|cds compile|deployment>" references/*.md srv db app) for narrow lookups before loading long guides
Overview
CAP (Cloud Application Programming Model) is a framework of languages, libraries, and tools for building enterprise-grade cloud applications. Core Data Services (CDS) is the universal modeling language: you model the domain with CDL, and generic runtimes serve the resulting service automatically (CRUD, deep reads/writes, drafts, media, search, pagination, auth, i18n) out of the box. Business rules go into event handlers, not data classes. CDS models compile to CSN (runtime object model) and are translated to native SQL DDL for deployment.
Layer
What it is
CDL → CSN → DDL
.cds files compile to CSN, deployed as SQL DDL; served as OData/REST/GraphQL/OpenAPI/AsyncAPI/MCP
Domain model
Entities + associations + aspects in db/. Plain passive data, no behavior
Application model
Services (srv/) as projections/views on domain model; interface inferred from projection elements
Service
Interface in CDS + implementation = sum of its event handlers
Events
Everything at runtime is an event. Handlers (on/before/after) = implementation; listeners = observers
Aspects
Aspect-oriented extension: annotate, extend — reuse, separation of concerns, customization
Associations
Forward-declared joins. Path expressions → JOINs, infix filters → SEMI JOINs. Use instead of raw FK columns
CAP uses profiles ([development], [production]) in package.json under cds.requires to switch db (sqlite vs hana), auth (mocked vs jwt/xsuaa), and messaging without changing code. Activate via NODE_ENV or cds env.
1. CDS Modeling Rules (Development)
Full reference: references/cds-modeling.md
Core Patterns
Rule
Why
Use cuid (UUID key), managed (CreatedAt/By, ModifiedAt/By), temporal aspects from @sap/cds/common
// Projections
SELECT from Books { ID, title, author.name as author }
// Path expressions (auto-JOIN)
SELECT from Authors[country.code='DE']:books { title }
// Infix filters (SEMI JOIN)
SELECT from Books { title } where author.country.code = 'US'
// Exists / aggregates
SELECT from Books where exists reviews[rating > 4]
SELECT from Books { author, count(*) as cnt } group by author having cnt > 5
2. Service Implementation (Node.js)
Full reference: references/services-and-handlers.md, references/nodejs-runtime.md
Handler Registration
// srv/catalog-service.jsmodule.exports = (srv) => {
// before = validation only (sync); do DB I/O in on/after
srv.before('CREATE', 'Books', (req) => {
if (!req.data.title) return req.error(400, 'title is required')
})
// after = result transformation (presentation)
srv.after('READ', 'Books', (books) => {
for (const b of books) b.netPrice = b.price
})
// on = domain logic (replaces generic handler; use next() to delegate)
srv.on('submitOrder', async (req) => {
const { book, quantity } = req.dataawaitUPDATE(Books, book).set`stock = stock - ${quantity}`
})
}
Phases & Semantics
Phase
Runs
Use For
Can Delegate (next())
before
Before on handlers; all listeners in parallel
Validation, read-only checks
No (listeners)
on
After before; interceptor stack
Domain logic, custom CRUD
Yes — await next() delegates to generic
after
After on; all listeners in parallel
Result enrichment, computed fields
No (listeners)
Request Context (req)
Property
Description
req.data
Payload (CREATE/UPDATE/UPSERT, action params)
req.query
CQN query object (SELECT/INSERT/...)
req.params
URL params (keys, action params)
req.user
Authenticated user (roles, attributes, tenant)
req.tenant
Tenant ID if multitenancy
req.timestamp
Transaction-wide consistent time — use for managed dates, never new Date()
entity Orders @(restrict: [
{ grant: ['READ','UPDATE','DELETE'], where: 'CreatedBy = $user' }, // own
{ grant: '*', to: 'admin' }
]) { ... }
// $user.<attr> is a LIST — empty list = fully restricted
// exists predicates for domain-driven auth:
where: 'exists members[userId = $user and role = "Editor"]'
Critical Review Rules
Rule
Violation = Automatic Fail
Every exposed service has @requires/@restrict
Service is wide open
Prefer one service per role (@requires) over mixed-role entities
Role confusion, leakage
@readonly ≠ authorization — it blocks writes but allows reads for all
PII exposed
Composition children NOT checked — only root entity auth applies
Child data bypasses auth
Only target entity checked; $expand/deep insert children NOT checked
Hidden association leakage
Avoid enumerable keys with instance-based auth (404 vs 403 disclosure)
Existence oracle
5. Node.js Best Practices
Full reference: references/nodejs-runtime.md
Do
Don't
Caret ranges ^9.1.0 for deps; engines: { node: ">=18" }
Exact-pin (breaks dedupe, fix delivery, CDS model reuse)
Commit + deploy package-lock.json; @sap/cds-dk in devDependencies
npm shrinkwrap when publishing a library
Mount helmet via cds.on('bootstrap', app => app.use(helmet()))
Assume security middlewares are auto-mounted
CSRF via App Router; CORS configured in exactly one place
Configure CORS in both App Router and CAP server
Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate on CSRF-token responses
Cache CSRF tokens
Fail loudly — let unexpected errors crash the request
Catch/handle unexpected errors; code defensively
Augment and re-throw the same error object
Replace/hide error origins
Decimal/Int64 arithmetic in the DB (set/with CQL)
Arithmetic on Decimal/Int64 in JS (precision loss)
req.timestamp for managed dates
new Date() / parsing time strings
Anonymous /health ping unauthenticated
Leave sophisticated health checks unauthenticated (DoS)
Transactions
// Auto: CAP wraps each request; req.timestamp identical
srv.before('CREATE', 'Orders', (req) => {
req.data.createdAt = req.timestamp// use this
})
// Manual when neededconst tx = cds.tx(req)
await tx.run(UPDATE(...))
await tx.commit() // or rollback on error
6. Code Review Checklist
Review in order. First three are HARD GATES — any failure = block merge.
Gate 1: Authorization (Zero Tolerance)
Gate 1: Authorization
Every service has @requires/@restrict (no @readonly as sole auth for PII)
Instance-based where with $user; @protocol: 'none' for internal services
Gate 2: Model Integrity
Keys = cuid; managed/temporal reused; associations over raw FKs
Domain values as enums with @assert; annotations out of db/ via aspects
Gate 3: Service Contract & Logic
Use-case projections per role; writes via actions; validation in before (sync)
Single-row checks use .first(); Decimal/Int64 arithmetic DB-side (set/.with)
Custom on READ preserves req.query; errors re-thrown; req.timestamp for dates
Security, Performance & Ops
helmet mounted; CSRF/CORS configured once; no secrets in repo
No N+1; caret ranges; package-lock.json committed; @sap/cds-dk in devDeps
cds.test() suites with mock auth and negative test assertions (401/403/404)
7. Verification Commands & Skill Structure
cds watch # dev server (SQLite in-memory, hot reload)
cds compile # validate models; cdsc --lint for strict checks
cds build # generate CSN/db artifacts
cds test# run test/ suites
Before claiming a change is done:cds compile passes + cds test passes.
8. Reference Links & Evidence Ledger
Full reference documentation links and verified evidence ledger trace details live in references/evidence-ledger.md.
Total: 8 reference files + 5 templates, ~5,500 lines of original, production-grade CAP reference material.