Skip to content

Commit 08b9942

Browse files
committed
docs: add detailed guidelines for CDS model review process and new skills for loading and testing data
1 parent 9d94ad5 commit 08b9942

7 files changed

Lines changed: 178 additions & 19 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
You are a CDS model reviewer for a multi-profile SAP CAP project (SAP HANA, SQLite, PostgreSQL).
2+
3+
## What to Review
4+
5+
When reviewing CDS model changes in this project, check each of the following:
6+
7+
### 1. Cross-Profile Consistency
8+
- New or modified entities in `cap/db/schema.cds` must be reflected in all profile-specific extensions:
9+
- `cap/db/hana/` (HANA-specific types, calculated views)
10+
- `cap/db/sqlite/` (SQLite workarounds, type mappings)
11+
- `cap/db/postgres/` (PostgreSQL-specific extensions)
12+
- Not every entity needs a profile extension, but check whether existing patterns suggest one is expected.
13+
14+
### 2. Junction Entity Patterns
15+
- Many-to-many relationships use explicit junction entities (e.g., `Film2People`, `Episode2Planets`).
16+
- New M:N relationships must follow this pattern — no unmanaged associations or link tables.
17+
- Junction entities should use `managed` + `cuid` from `@sap/cds/common`.
18+
- Service projections must use `redirected to` for junction navigation.
19+
20+
### 3. Service Exposure
21+
- New entities should be exposed in the relevant `*-service.cds` file.
22+
- Check that the entity is listed in `cap/srv/services-auth.cds` with an appropriate `@requires` annotation.
23+
24+
### 4. Annotation Separation
25+
- Fiori/UI annotations belong in `*-fiori.cds` files only — never in `*-service.cds`.
26+
- `Common.ValueList` and `UI.SelectionFields` patterns should be consistent with existing entities.
27+
28+
### 5. View Declarations
29+
- Aggregation views like `Show2Planets` (defined as `define view ... as select from Episode2*`) are not physical tables — verify new views follow this pattern when aggregating over junction tables.
30+
31+
### 6. Build Verification
32+
- Run `cd cap && npm run build` to confirm CDS compilation succeeds.
33+
- If the build fails, report the exact compiler error.
34+
35+
## Tools
36+
- Use `cds-mcp` to resolve entity and field definitions.
37+
- Use Grep/Read to check profile extensions and service files.
38+
- Run `npm run build` in `cap/` to verify compilation.
39+
40+
## Output
41+
Report findings as a checklist with pass/fail status for each category. Flag issues with file paths and line numbers.

.claude/settings.json

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,33 @@
1111
"Bash(node --test --test-reporter=tap scripts/scraper/test/extractors.test.js)",
1212
"Bash(node -e ':*)",
1313
"Bash(node --test --test-reporter=tap D:/projects/cloud-cap-hana-swapi/scripts/scraper/test/extractors.test.js)",
14-
"Bash(grep -n \"extractSeasonEpisodeTitles\\\\|seasons\" /d/projects/cloud-cap-hana-swapi/scripts/scraper/*.js)"
14+
"Bash(grep -n \"extractSeasonEpisodeTitles\\\\|seasons\" /d/projects/cloud-cap-hana-swapi/scripts/scraper/*.js)",
15+
"Bash(node -e \"const data = require\\('./scripts/data/raw/planets.json'\\); console.log\\('Planet count:', data.length || Object.keys\\(data\\).length\\);\")",
16+
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\('Count:', len\\(d\\)\\)\")"
17+
]
18+
},
19+
"hooks": {
20+
"PreToolUse": [
21+
{
22+
"matcher": "Edit|Write|Read",
23+
"hooks": [
24+
{
25+
"type": "command",
26+
"command": "bash -c 'FILE=$(echo \"$TOOL_INPUT\" | sed -n \"s/.*\\\"file_path\\\"[[:space:]]*:[[:space:]]*\\\"\\([^\\\"]*\\)\\\".*/\\1/p\"); case \"$FILE\" in *cdsrc-private*|*default-env*) echo \"BLOCKED: $FILE contains credentials — do not read or modify\"; exit 1;; *) exit 0;; esac'"
27+
}
28+
]
29+
}
30+
],
31+
"PostToolUse": [
32+
{
33+
"matcher": "Edit|Write",
34+
"hooks": [
35+
{
36+
"type": "command",
37+
"command": "bash -c 'FILE=$(echo \"$TOOL_INPUT\" | sed -n \"s/.*\\\"file_path\\\"[[:space:]]*:[[:space:]]*\\\"\\([^\\\"]*\\)\\\".*/\\1/p\"); case \"$FILE\" in *.cds) cd d:/projects/cloud-cap-hana-swapi/cap && node node_modules/eslint/bin/eslint.js --no-error-on-unmatched-pattern \"$FILE\" 2>&1 | tail -20 || true;; *) exit 0;; esac'"
38+
}
39+
]
40+
}
1541
]
1642
}
1743
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
name: load-and-test
3+
description: Rebuild CDS artifacts, reload SQLite fixture data, and run the full test suite. Use after schema or service changes.
4+
disable-model-invocation: true
5+
---
6+
7+
Run the following commands **sequentially** from the `cap/` directory. Each step depends on the previous one succeeding.
8+
9+
## Steps
10+
11+
1. **Build CDS artifacts and typed models**
12+
```bash
13+
cd cap && npm run build
14+
```
15+
This runs `cds build` and regenerates `@cds-models/` via `@cap-js/cds-typer`.
16+
17+
2. **Reload SQLite fixture data**
18+
```bash
19+
cd cap && npm run load_sqlite
20+
```
21+
Runs `convertData.js` with the SQLite profile to populate `db.sqlite`.
22+
23+
3. **Run full test suite**
24+
```bash
25+
cd cap && npm test
26+
```
27+
Runs model + handler tests with a 60-second timeout.
28+
29+
## Rules
30+
31+
- **Stop on failure.** If any step fails, report the error immediately. Do not continue to the next step.
32+
- **Report results.** After all steps pass, summarize: build status, data load count, and test results (pass/fail/skip counts).
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
name: scrape-and-load
3+
description: Run the Wookieepedia scraper, convert data, load into SQLite, and verify with migration and full tests.
4+
disable-model-invocation: true
5+
---
6+
7+
Run the full data pipeline **sequentially** from the `cap/` directory.
8+
9+
## Steps
10+
11+
1. **Scrape Star Wars data**
12+
```bash
13+
cd cap && npm run scrape
14+
```
15+
Uses committed cache by default (fast). If the user requests `--bypass-cache`, ask for explicit confirmation first, then run `npm run scrape:bypass-cache` instead.
16+
17+
2. **Build CDS artifacts**
18+
```bash
19+
cd cap && npm run build
20+
```
21+
22+
3. **Load fixture data into SQLite**
23+
```bash
24+
cd cap && npm run load_sqlite
25+
```
26+
27+
4. **Run migration tests**
28+
```bash
29+
cd cap && npm run test:migration
30+
```
31+
Verifies data conversion logic and report generation.
32+
33+
5. **Run full test suite**
34+
```bash
35+
cd cap && npm test
36+
```
37+
38+
## Rules
39+
40+
- **Stop on failure.** If any step fails, report the error and do not continue.
41+
- **Cache-first by default.** Never bypass the scraper cache without user confirmation — fresh fetches hit Wookieepedia and take significantly longer.
42+
- **Report results.** Summarize each step's outcome: scrape stats, build status, load counts, and test pass/fail/skip.

CLAUDE.md

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@ npm run test:profile # Fast regression gate — use before committing
2525
npm run test:migration # Data conversion/loading tests
2626

2727
# Build & Deploy
28-
npm run build # CDS build + generate artifacts (required before HANA deployment)
28+
npm run build # CDS build + generate typed models (required before HANA deployment)
29+
npm run types # Regenerate CDS typed models → @cds-models/
2930
npm run build_sqlite # Deploy schema to SQLite
3031
npm run build_pg # Deploy schema to PostgreSQL
3132
npm run hana # Deploy to HANA HDI container ("starwars")
3233

3334
# Data loading
3435
npm run load # Load Star Wars fixture data (hybrid/HANA profile)
3536
npm run load_sqlite # Load fixture data into SQLite
37+
npm run load_pg # Load fixture data into PostgreSQL
3638

3739
# Data scraping
3840
npm run scrape # full run, cache-first (fast — uses committed cache)
@@ -57,12 +59,16 @@ After any CDS model changes, run `npm run build` in `cap/` to regenerate artifac
5759

5860
```
5961
cap/db/ Domain model + persistence (*.cds), profile-specific extensions
62+
cap/db/src/ HANA migration tables (.hdbmigrationtable) for schema evolution
63+
cap/db/last-dev/ Last-deployed CSN snapshot (used by HANA schema migration)
6064
cap/srv/ Service layer: contracts (*-service.cds), Fiori annotations (*-fiori.cds),
6165
authorization (services-auth.cds), runtime handlers (*.js), server config (server.js)
62-
cap/app/ UI frontends (Fiori preview)
66+
cap/app/ UI frontends — five apps: film/, people/, show/, media/ (Fiori Elements),
67+
viewer/ (custom HTML/JS app)
6368
cap/test/ Automated tests by layer (model, handler, data migration)
6469
cap/docs/ Generated docs (OpenAPI, AsyncAPI) and learning materials
6570
cap/labs/ Hands-on exercises (lab-01 through lab-05)
71+
cap/@cds-models/ Generated CDS typed models (via @cap-js/cds-typer, git-ignored)
6672
```
6773

6874
### Domain Model (`cap/db/schema.cds`)
@@ -77,13 +83,20 @@ Profile-specific extensions live in `cap/db/hana/`, `cap/db/sqlite/`, `cap/db/po
7783

7884
### Service Layer (`cap/srv/`)
7985

80-
Six domain services (one per entity): `StarWarsFilm`, `StarWarsPeople`, `StarWarsPlanet`, `StarWarsSpecies`, `StarWarsStarship`, `StarWarsVehicle`. A seventh service, `StarWarsEpisode`, exposes `Episodes` and `Episode2*` junctions as read-only projections (no handler logic required). Protocols: OData v4 (primary), OData v2 (adapter), GraphQL (`/graphql`), REST.
86+
Nine services total:
87+
88+
- **Six core entity services**: `StarWarsFilm`, `StarWarsPeople`, `StarWarsPlanet`, `StarWarsSpecies`, `StarWarsStarship`, `StarWarsVehicle`
89+
- **`StarWarsShow`**: Full service exposing `Show`, `Episode`, `Media`, `MediaCharacters`, `Show2People`, `Show2Planets`, and related projections. Has handler logic in `show-service.js` (computes virtual `edit_url` on `Media` reads).
90+
- **`StarWarsEpisode`**: Read-only projections of `Episodes` and `Episode2*` junctions (no handler logic). Separate CDS file with its own Fiori annotations.
91+
- **`DataService`** (`/-data`): Entity metadata/introspection service exposing entity names, columns, and types. Handler in `data-service.js`.
92+
93+
Protocols: OData v4 (primary), OData v2 (adapter), GraphQL (`/graphql`), REST.
8194

8295
**Critical file separation rule:**
8396
- Service contracts → `*-service.cds`
8497
- Fiori/UI annotations → `*-fiori.cds` (never mix into service contracts)
85-
- Authorization → `services-auth.cds` (centralized; roles: `Viewer`, `Editor`, `Admin`)
86-
- Runtime logic → `*.js` handlers
98+
- Authorization → `services-auth.cds` (centralized; currently all services use `@requires: 'any'` — fully public. Roles `Viewer`, `Editor`, `Admin` exist as commented-out showcase examples)
99+
- Runtime logic → `*.js` handlers (four files: `server.js`, `people-service.js`, `show-service.js`, `data-service.js`)
87100

88101
### Handler Patterns (`cap/srv/*.js`)
89102

@@ -124,14 +137,19 @@ npm run build # copies content + builds to site/.vitepress/dist/
124137
npm run preview # preview the built site
125138
```
126139

127-
GitHub Actions auto-deploys to GitHub Pages on push to `main` when files under `site/**`, `cap/docs/**`, `cap/labs/**/README.md`, or `HANA_CLI_*.md` change (`.github/workflows/docs.yml`).
128-
129140
**Do not commit generated dirs** (`site/guide/`, `site/architecture/`, `site/labs/`, `site/reference/`, `site/api/`, `site/hana-cli/`) — they are git-ignored and regenerated at build time.
130141

142+
## CI/CD
143+
144+
Two GitHub Actions workflows in `.github/workflows/`:
145+
146+
- **`docs.yml`** — auto-deploys the VitePress site to GitHub Pages on push to `main` when `site/**`, `cap/docs/**`, `cap/labs/**/README.md`, `HANA_CLI_*.md`, or `CHANGELOG.md` change.
147+
- **`migration-tests.yml`** — runs migration unit tests (`npm run test:migration`) on push/PR when `convertData.js`, `convertDataLite.js`, or their tests change.
148+
131149
## Key Conventions
132150

133151
- **CDS modeling**: Preserve namespace and `managed`/`cuid` patterns. Prefer explicit many-to-many junction entities. Keep `Common.ValueList` and `UI.*` patterns consistent.
134-
- **Breaking changes**: Avoid renames/removals without migration intent. See `docs/value-help-migration.md` for a past breaking-change example.
135-
- **Data loading**: Use `convertData.js` for all profiles (handles parallel chunk loading; SQLite-safe). The `load_sqlite` npm script invokes this directly.
136-
- **Generated folders**: `cap/gen/` is auto-generated. After HANA deployment, re-run `npm run build` if `gen/srv` is cleared.
152+
- **Breaking changes**: Avoid renames/removals without migration intent. See `cap/docs/value-help-migration.md` for a past breaking-change example.
153+
- **Data loading**: `convertData.js` handles all profiles (parallel chunk loading; SQLite-safe). `convertDataLite.js` is a lightweight wrapper used by CI. The `load_sqlite` npm script invokes `convertData.js` directly.
154+
- **Generated folders**: `cap/gen/` and `cap/@cds-models/` are auto-generated. After HANA deployment, re-run `npm run build` if `gen/srv` is cleared.
137155
- **cds-mcp**: When editing CDS files, resolve entity/field definitions with `cds-mcp` before modifying models, and check CAP docs via `cds-mcp` before proposing CDS syntax or API usage.

cap/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cap-hana-swapi",
3-
"version": "2.0.0",
3+
"version": "2.0.1",
44
"description": "SAP Cloud Application Programming Model fun sample to demonstrate many-to-many relationships.",
55
"repository": "https://github.com/SAP-samples/cloud-cap-hana-swapi",
66
"license": "Apache-2.0",
@@ -14,15 +14,15 @@
1414
"@cap-js/postgres": "^2.2.0",
1515
"@cap-js/sqlite": "^2.2.0",
1616
"@cap-js/telemetry": "^1.6.0",
17-
"@sap-cloud-sdk/resilience": "^4.5.1",
18-
"@sap/cds": "9.8.4",
17+
"@sap-cloud-sdk/resilience": "^4.6.0",
18+
"@sap/cds": "9.8.5",
1919
"@sap/cds-common-content": "^3.1.0",
2020
"@sap/cds-fiori": "^2.3.0",
2121
"@sap/xb-msg-amqp-v100": "^0.9.58",
2222
"cds-swagger-ui-express": "^0.11.0",
2323
"cors": "^2.8.6",
2424
"express": "^5.2.1",
25-
"uuid": "^13.0.0"
25+
"uuid": "^14.0.0"
2626
},
2727
"engines": {
2828
"node": ">=20"
@@ -162,10 +162,10 @@
162162
},
163163
"devDependencies": {
164164
"@cap-js/cds-test": "^0.4.1",
165-
"@sap/dev-cap-tools": "^1.53.1",
165+
"@sap/dev-cap-tools": "^1.53.2",
166166
"@sap/eslint-plugin-cds": "^4.2.1",
167167
"@sap/hdi-deploy": "^5.6.1",
168-
"eslint": "10.2.0",
168+
"eslint": "10.2.1",
169169
"stringify-changelog": "^0.2.1",
170170
"widdershins": "^4.0.1",
171171
"@cap-js/cds-typer": ">=0.1"

docs/superpowers/specs/2026-04-17-tip-rotation-design.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ type Config struct {
3232
}
3333
```
3434

35-
`Default()` sets `Tip: TipConfig{Rotation: "daily"}`. An empty `Rotation` string is treated as `"daily"` so existing config files without the key continue to work.
35+
`Default()` leaves `Rotation` as `""` (the Go zero value). `tipSeed` treats `""` as `"daily"` at runtime, so existing config files without a `tip` block behave identically to new configs.
3636

37-
The `tip` block is omitted from `config.yaml` until the user explicitly sets a value (`omitempty`).
37+
The `tip` block is omitted from `config.yaml` until the user explicitly sets a value `TipConfig{Rotation: ""}` is the zero value and `omitempty` suppresses it.
3838

3939
---
4040

0 commit comments

Comments
 (0)