Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6780272
docs(admin): design spec for Tutorials OP enhancements (categories/co…
jung-thomas Aug 31, 2026
abfe446
docs(admin): record approved decisions (D1-D3) in OP enhancements spec
jung-thomas Aug 31, 2026
7f569ac
docs(admin): Phase 1 implementation plan (WS1-3 empty facets)
jung-thomas Aug 31, 2026
158f7e6
docs(admin): Phase 2 (media/freshness) + Phase 3 (KG) implementation …
jung-thomas Aug 31, 2026
5f74833
feat(publish): self-heal categories via classifyAndPersist after upse…
jung-thomas Aug 31, 2026
170965e
test(publish): hybrid guard for category population (#WS1)
jung-thomas Aug 31, 2026
67a5369
feat(db): add GitHub link columns to TutorialContributors (#WS2)
jung-thomas Aug 31, 2026
809a433
fix(db): emit HANA migration=3 for TutorialContributors GitHub column…
jung-thomas Aug 31, 2026
6c20476
feat(fetch): write contributors sidecar from git contributor list (#WS2)
jung-thomas Aug 31, 2026
27386a5
feat(publish): server REPLACE handler for TutorialContributors (#WS2)
jung-thomas Aug 31, 2026
48ffdce
feat(publish): non-fatal client step to publish contributors sidecars…
jung-thomas Aug 31, 2026
5e9192c
feat(admin-ui): GitHub-linked login column on Contributors table (#WS2)
jung-thomas Aug 31, 2026
7104490
test(publish): hybrid guard for contributor linking (#WS2)
jung-thomas Aug 31, 2026
2847256
feat(db): add TutorialValidationRules entity for all rules.vr rules (…
jung-thomas Aug 31, 2026
5e32029
feat(parser): collectAllRules for full rules.vr rule set (#WS3)
jung-thomas Aug 31, 2026
464296a
feat(fetch): write validation-rules sidecar (all rule types) (#WS3)
jung-thomas Aug 31, 2026
bbba5c3
feat(publish): server REPLACE handler for TutorialValidationRules (#WS3)
jung-thomas Aug 31, 2026
2018592
feat(publish): non-fatal client step to publish validation-rules side…
jung-thomas Aug 31, 2026
72b0a98
feat(admin-ui): All Validation Rules facet + relabel AI facet (#WS3)
jung-thomas Aug 31, 2026
6969b24
test(publish): hybrid guard for all-rules population (#WS3)
jung-thomas Aug 31, 2026
47f10e3
fix(db): align last-dev/csn.json with canonical cds build ordering
jung-thomas Aug 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .deploy/mta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ modules:
- cp -r ../../hugo/assets ./hugo/assets
- cp -r ../../hugo/data ./hugo/data
- cp -r ../../hugo/i18n ./hugo/i18n
- bash -c "mkdir -p srv/jobs && mkdir -p srv/handlers && mkdir -p srv/lib/branch && mkdir -p srv/lib/runtime-config && mkdir -p srv/lib/prompts && mkdir -p srv/lib/kg && mkdir -p srv/mcp/prompts && cp ../../srv/lib/branch/condition.js ../../srv/lib/branch/engine.js ../../srv/lib/branch/ranker.js ../../srv/lib/branch/user-state.js ../../srv/lib/branch/loaders.js ../../srv/lib/branch/mission-detail.js ../../srv/lib/branch/slug-key.js ../../srv/lib/branch/decide.js ../../srv/lib/branch/joule-tool.js ../../srv/lib/branch/branch-telemetry.js ../../srv/lib/branch/group-by-alt.js ../../srv/lib/branch/profile-fields.js ../../srv/lib/branch/profile-override.js srv/lib/branch/ && cp ../../srv/lib/runtime-config/kg-settings.js ../../srv/lib/runtime-config/ui-events-settings.js ../../srv/lib/runtime-config/search-settings.js ../../srv/lib/runtime-config/navigator-settings.js ../../srv/lib/runtime-config/display-settings.js ../../srv/lib/runtime-config/tenant-settings.js ../../srv/lib/runtime-config/alert-settings.js srv/lib/runtime-config/ && cp ../../srv/lib/kg/on-demand-enqueue.js ../../srv/lib/kg/on-demand-cosine-rank.js srv/lib/kg/ && cp ../../srv/lib/credstore.js ../../srv/lib/secret-resolver.js ../../srv/lib/content-store.js ../../srv/lib/content-delta-flags.js ../../srv/lib/content-cache-coherence.js ../../srv/lib/edge-cache-headers.js ../../srv/lib/content-publish-session.js ../../srv/lib/resolve-tutorial-author.js ../../srv/lib/_tutorials-table.js ../../srv/lib/catalog-renderer.js ../../srv/lib/catalog-data.js ../../srv/lib/catalog-mission-hierarchy.js ../../srv/lib/chrome-shell.js ../../srv/lib/pipeline-log.js ../../srv/lib/legacy-id.js ../../srv/lib/embedding-pipeline.js ../../srv/lib/step-text-extractor.js ../../srv/lib/embedding-client.js ../../srv/lib/step-vectors.js ../../srv/lib/user-progress.js ../../srv/lib/co-completion.js ../../srv/lib/tutorial-centroid.js ../../srv/lib/tag-label-map.js ../../srv/lib/code-check-tool.js ../../srv/lib/code-check-prompt.js ../../srv/lib/code-check-handler.js ../../srv/lib/code-check-llm.js ../../srv/lib/code-check-step-loader.js ../../srv/lib/code-check-spec-publish.js ../../srv/lib/validate-answer-spec-publish.js ../../srv/lib/category-classifier.js ../../srv/lib/category-classifier-llm.js ../../srv/lib/category-seed-embeddings.js ../../srv/lib/build-catalog-categories.js ../../srv/lib/chat-settings-resolver.js ../../srv/lib/kg-extract.js ../../srv/lib/kg-queries.js ../../srv/lib/kg-projection.js ../../srv/lib/kg-similarity.js ../../srv/lib/kg-cycles.js ../../srv/lib/kg-graph-rebuild.js ../../srv/lib/kg-sparql-client.js ../../srv/lib/kg-merge-pair.js ../../srv/lib/kg-concept-loader.js ../../srv/lib/kg-neighborhood-cache.js ../../srv/lib/kg-neighborhood-merge.js ../../srv/lib/kg-neighborhood-full-helpers.js ../../srv/lib/kg-other-resources-loader.js ../../srv/lib/kg-stamp-meta-text.js ../../srv/lib/kg-tutorial-teaches-map.js ../../srv/lib/kg-resource-type-config.js ../../srv/lib/kg-meta-formatters.js ../../srv/lib/discovery-mission-categories.js ../../srv/lib/external-content-ttl.js ../../srv/lib/recompute-tutorial-progress-bulk-sql.js ../../srv/lib/youtube-fetcher.js ../../srv/lib/homepage-events-merger.js ../../srv/lib/homepage-rss-fetcher.js ../../srv/lib/rss-parse.js ../../srv/lib/community-blogs-fetcher.js ../../srv/lib/community-blog-source-defaults.js ../../srv/lib/community-blogs-classifier.js ../../srv/lib/safe-fetch.js ../../srv/lib/curl-transport.js ../../srv/lib/khoros-transport.js ../../srv/lib/explainer-generator.js ../../srv/lib/_token-cost.js ../../srv/lib/metrics.js ../../srv/lib/alerting.js ../../srv/lib/relevance-classifier.js ../../srv/lib/relevance-seed-embeddings.js ../../srv/lib/relevance-keyword-rules.js ../../srv/lib/canonicalize-link.js ../../srv/lib/detect-language-en.js ../../srv/lib/kg-community-coverage.js ../../srv/lib/page-key-map.js ../../srv/lib/page-fallback.js ../../srv/lib/task-record-submission-id.js ../../srv/lib/image-store.cjs ../../srv/lib/image-ingest.cjs ../../srv/lib/image-source-handler.js ../../srv/lib/img-cdn-fetch.cjs ../../srv/lib/img-cdn-retry.cjs ../../srv/lib/image-warm-utils.js ../../srv/lib/attachment-store.cjs ../../srv/lib/attachment-ingest.cjs ../../srv/lib/attachment-mime.cjs ../../srv/lib/attachment-warm-utils.js ../../srv/lib/attachment-source-handler.js ../../srv/lib/attachment-ingest-handler.js ../../srv/lib/island-manifest.json srv/lib/ && mkdir -p srv/lib/feature-flags && cp ../../srv/lib/feature-flags/db-flags.js ../../srv/lib/feature-flags/registry.js srv/lib/feature-flags/ && cp ../../srv/handlers/categories-after-hooks.js ../../srv/handlers/completion-path-items-altgroup.js srv/handlers/ && mkdir -p srv && cp ../../srv/content-moderation-service.js srv/ && cp ../../srv/jobs/consolidate-concepts-job.js ../../srv/jobs/extract-concepts-job.js ../../srv/jobs/job-lock.js ../../srv/jobs/secret-expiry-check.js ../../srv/jobs/homepage-link-health.js ../../srv/jobs/kg-ondemand-job.js ../../srv/jobs/community-blogs-fetch-job.js ../../srv/jobs/community-blogs-classify-job.js ../../srv/jobs/fetch-news-job.js srv/jobs/ && cp ../../srv/lib/prompts/explainer-verb.md ../../srv/lib/prompts/explainer-shelf.md ../../srv/lib/prompts/explainer-shelf-entry.md ../../srv/lib/prompts/community-blogs-classifier.md srv/lib/prompts/ && cp ../../srv/mcp/prompts/summarize_mission_for_beginner.md ../../srv/mcp/prompts/generate_lab_exercise.md ../../srv/mcp/prompts/explain_concept.md ../../srv/mcp/prompts/suggest_learning_path.md srv/mcp/prompts/"
- bash -c "mkdir -p srv/jobs && mkdir -p srv/handlers && mkdir -p srv/lib/branch && mkdir -p srv/lib/runtime-config && mkdir -p srv/lib/prompts && mkdir -p srv/lib/kg && mkdir -p srv/mcp/prompts && cp ../../srv/lib/branch/condition.js ../../srv/lib/branch/engine.js ../../srv/lib/branch/ranker.js ../../srv/lib/branch/user-state.js ../../srv/lib/branch/loaders.js ../../srv/lib/branch/mission-detail.js ../../srv/lib/branch/slug-key.js ../../srv/lib/branch/decide.js ../../srv/lib/branch/joule-tool.js ../../srv/lib/branch/branch-telemetry.js ../../srv/lib/branch/group-by-alt.js ../../srv/lib/branch/profile-fields.js ../../srv/lib/branch/profile-override.js srv/lib/branch/ && cp ../../srv/lib/runtime-config/kg-settings.js ../../srv/lib/runtime-config/ui-events-settings.js ../../srv/lib/runtime-config/search-settings.js ../../srv/lib/runtime-config/navigator-settings.js ../../srv/lib/runtime-config/display-settings.js ../../srv/lib/runtime-config/tenant-settings.js ../../srv/lib/runtime-config/alert-settings.js srv/lib/runtime-config/ && cp ../../srv/lib/kg/on-demand-enqueue.js ../../srv/lib/kg/on-demand-cosine-rank.js srv/lib/kg/ && cp ../../srv/lib/credstore.js ../../srv/lib/secret-resolver.js ../../srv/lib/content-store.js ../../srv/lib/content-delta-flags.js ../../srv/lib/content-cache-coherence.js ../../srv/lib/edge-cache-headers.js ../../srv/lib/content-publish-session.js ../../srv/lib/resolve-tutorial-author.js ../../srv/lib/_tutorials-table.js ../../srv/lib/catalog-renderer.js ../../srv/lib/catalog-data.js ../../srv/lib/catalog-mission-hierarchy.js ../../srv/lib/chrome-shell.js ../../srv/lib/pipeline-log.js ../../srv/lib/legacy-id.js ../../srv/lib/embedding-pipeline.js ../../srv/lib/step-text-extractor.js ../../srv/lib/embedding-client.js ../../srv/lib/step-vectors.js ../../srv/lib/user-progress.js ../../srv/lib/co-completion.js ../../srv/lib/tutorial-centroid.js ../../srv/lib/tag-label-map.js ../../srv/lib/code-check-tool.js ../../srv/lib/code-check-prompt.js ../../srv/lib/code-check-handler.js ../../srv/lib/code-check-llm.js ../../srv/lib/code-check-step-loader.js ../../srv/lib/code-check-spec-publish.js ../../srv/lib/validate-answer-spec-publish.js ../../srv/lib/category-classifier.js ../../srv/lib/category-classifier-llm.js ../../srv/lib/category-seed-embeddings.js ../../srv/lib/build-catalog-categories.js ../../srv/lib/chat-settings-resolver.js ../../srv/lib/kg-extract.js ../../srv/lib/kg-queries.js ../../srv/lib/kg-projection.js ../../srv/lib/kg-similarity.js ../../srv/lib/kg-cycles.js ../../srv/lib/kg-graph-rebuild.js ../../srv/lib/kg-sparql-client.js ../../srv/lib/kg-merge-pair.js ../../srv/lib/kg-concept-loader.js ../../srv/lib/kg-neighborhood-cache.js ../../srv/lib/kg-neighborhood-merge.js ../../srv/lib/kg-neighborhood-full-helpers.js ../../srv/lib/kg-other-resources-loader.js ../../srv/lib/kg-stamp-meta-text.js ../../srv/lib/kg-tutorial-teaches-map.js ../../srv/lib/kg-resource-type-config.js ../../srv/lib/kg-meta-formatters.js ../../srv/lib/discovery-mission-categories.js ../../srv/lib/external-content-ttl.js ../../srv/lib/recompute-tutorial-progress-bulk-sql.js ../../srv/lib/youtube-fetcher.js ../../srv/lib/homepage-events-merger.js ../../srv/lib/homepage-rss-fetcher.js ../../srv/lib/rss-parse.js ../../srv/lib/community-blogs-fetcher.js ../../srv/lib/community-blog-source-defaults.js ../../srv/lib/community-blogs-classifier.js ../../srv/lib/safe-fetch.js ../../srv/lib/curl-transport.js ../../srv/lib/khoros-transport.js ../../srv/lib/explainer-generator.js ../../srv/lib/_token-cost.js ../../srv/lib/metrics.js ../../srv/lib/alerting.js ../../srv/lib/relevance-classifier.js ../../srv/lib/relevance-seed-embeddings.js ../../srv/lib/relevance-keyword-rules.js ../../srv/lib/canonicalize-link.js ../../srv/lib/detect-language-en.js ../../srv/lib/kg-community-coverage.js ../../srv/lib/page-key-map.js ../../srv/lib/page-fallback.js ../../srv/lib/task-record-submission-id.js ../../srv/lib/image-store.cjs ../../srv/lib/image-ingest.cjs ../../srv/lib/image-source-handler.js ../../srv/lib/img-cdn-fetch.cjs ../../srv/lib/img-cdn-retry.cjs ../../srv/lib/image-warm-utils.js ../../srv/lib/attachment-store.cjs ../../srv/lib/attachment-ingest.cjs ../../srv/lib/attachment-mime.cjs ../../srv/lib/attachment-warm-utils.js ../../srv/lib/attachment-source-handler.js ../../srv/lib/attachment-ingest-handler.js ../../srv/lib/contributors-publish.js ../../srv/lib/validation-rules-publish.js ../../srv/lib/island-manifest.json srv/lib/ && mkdir -p srv/lib/feature-flags && cp ../../srv/lib/feature-flags/db-flags.js ../../srv/lib/feature-flags/registry.js srv/lib/feature-flags/ && cp ../../srv/handlers/categories-after-hooks.js ../../srv/handlers/completion-path-items-altgroup.js srv/handlers/ && mkdir -p srv && cp ../../srv/content-moderation-service.js srv/ && cp ../../srv/jobs/consolidate-concepts-job.js ../../srv/jobs/extract-concepts-job.js ../../srv/jobs/job-lock.js ../../srv/jobs/secret-expiry-check.js ../../srv/jobs/homepage-link-health.js ../../srv/jobs/kg-ondemand-job.js ../../srv/jobs/community-blogs-fetch-job.js ../../srv/jobs/community-blogs-classify-job.js ../../srv/jobs/fetch-news-job.js srv/jobs/ && cp ../../srv/lib/prompts/explainer-verb.md ../../srv/lib/prompts/explainer-shelf.md ../../srv/lib/prompts/explainer-shelf-entry.md ../../srv/lib/prompts/community-blogs-classifier.md srv/lib/prompts/ && cp ../../srv/mcp/prompts/summarize_mission_for_beginner.md ../../srv/mcp/prompts/generate_lab_exercise.md ../../srv/mcp/prompts/explain_concept.md ../../srv/mcp/prompts/suggest_learning_path.md srv/mcp/prompts/"
- bash -c "node -e \"const p=require('./package.json'); p.dependencies=Object.assign(p.dependencies||{},{cheerio:'^1.2.0','@sap-ai-sdk/foundation-models':'^2.10.0'}); require('fs').writeFileSync('./package.json', JSON.stringify(p,null,2));\""
properties:
EXPOSE_CAP_UI: false
Expand Down
19 changes: 18 additions & 1 deletion app/admin-annotations.cds
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,14 @@ annotate AdminService.Tutorials with {

annotate AdminService.TutorialContributors with {
name @Common.Label: 'Name';
login @Common.Label: 'GitHub';
email @Common.Label: 'Email';
role @Common.Label: 'Role';
};

annotate AdminService.TutorialContributors with @UI.LineItem: [
{ Value: name },
{ $Type: 'UI.DataFieldWithUrl', Value: login, Url: profileUrl, Label: 'GitHub' },
{ Value: email },
{ Value: role }
];
Expand Down Expand Up @@ -881,6 +883,19 @@ annotate AdminService.ValidateAnswerSpecs with @UI: {
}
};

// TutorialValidationRules — all validation rules for a tutorial (step, question,
// type, rule, AI-grading flag, correct answer). Joined via `validationRules` association.
annotate AdminService.TutorialValidationRules with @(
UI.LineItem: [
{ Value: stepNumber, Label: 'Step' },
{ Value: questionText, Label: 'Question' },
{ Value: questionType, Label: 'Type' },
{ Value: ruleType, Label: 'Rule' },
{ Value: aiGrading, Label: 'AI-Graded' },
{ Value: correctAnswer, Label: 'Correct Answer' }
]
);

// CodeCheckSpecs — per-step code-check specs (goal + reference solution).
// Joined via `codeCheckSpecs` association.
annotate AdminService.CodeCheckSpecs with {
Expand Down Expand Up @@ -954,8 +969,10 @@ annotate AdminService.Tutorials with @UI: {
{ $Type: 'UI.ReferenceFacet', Label: 'Contributors', ID: 'ContributorsFacet', Target: 'contributors/@UI.LineItem' },
{ $Type: 'UI.ReferenceFacet', Label: 'Completion Stats', ID: 'CompletionStatsFacet',
Target: 'completionStats/@UI.FieldGroup#Stats' },
{ $Type: 'UI.ReferenceFacet', Label: 'Validation Questions', ID: 'ValidationSpecsFacet',
{ $Type: 'UI.ReferenceFacet', Label: 'AI-Graded Validation', ID: 'ValidationSpecsFacet',
Target: 'validationSpecs/@UI.LineItem' },
{ $Type: 'UI.ReferenceFacet', Label: 'All Validation Rules', ID: 'AllValidationRulesFacet',
Target: 'validationRules/@UI.LineItem' },
{ $Type: 'UI.ReferenceFacet', Label: 'Code-Check Specs', ID: 'CodeCheckSpecsFacet',
Target: 'codeCheckSpecs/@UI.LineItem' },
{ $Type: 'UI.ReferenceFacet', Label: 'AI-Author Requests', ID: 'AiRequestsFacet',
Expand Down
75 changes: 75 additions & 0 deletions db/last-dev/csn.json
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,21 @@
"length": 50,
"@cds.persistence.name": "ROLE"
},
"login": {
"type": "cds.String",
"length": 255,
"@cds.persistence.name": "LOGIN"
},
"avatarUrl": {
"type": "cds.String",
"length": 1024,
"@cds.persistence.name": "AVATARURL"
},
"profileUrl": {
"type": "cds.String",
"length": 1024,
"@cds.persistence.name": "PROFILEURL"
},
"user_ID": {
"type": "cds.String",
"length": 36,
Expand Down Expand Up @@ -1457,6 +1472,66 @@
},
"@cds.persistence.name": "COM_SAP_DEVELOPERS_IMS_DEVELOPERENVIRONMENTLINKS"
},
"com.sap.developers.ims.TutorialValidationRules": {
"kind": "entity",
"@cds.persistence.journal": true,
"elements": {
"tutorial_ID": {
"type": "cds.String",
"length": 36,
"@odata.foreignKey4": "tutorial",
"key": true,
"@cds.persistence.name": "TUTORIAL_ID"
},
"stepNumber": {
"key": true,
"type": "cds.Integer",
"@cds.persistence.name": "STEPNUMBER"
},
"questionId": {
"key": true,
"type": "cds.String",
"length": 100,
"@cds.persistence.name": "QUESTIONID"
},
"questionText": {
"type": "cds.String",
"length": 2000,
"@cds.persistence.name": "QUESTIONTEXT"
},
"ruleType": {
"type": "cds.String",
"length": 50,
"@cds.persistence.name": "RULETYPE"
},
"questionType": {
"type": "cds.String",
"length": 20,
"@cds.persistence.name": "QUESTIONTYPE"
},
"choiceMode": {
"type": "cds.String",
"length": 20,
"@cds.persistence.name": "CHOICEMODE"
},
"options": {
"type": "cds.LargeString",
"@cds.persistence.name": "OPTIONS"
},
"correctAnswer": {
"type": "cds.LargeString",
"@cds.persistence.name": "CORRECTANSWER"
},
"aiGrading": {
"type": "cds.Boolean",
"default": {
"val": false
},
"@cds.persistence.name": "AIGRADING"
}
},
"@cds.persistence.name": "COM_SAP_DEVELOPERS_IMS_TUTORIALVALIDATIONRULES"
},
"com.sap.developers.ims.Puzzles": {
"kind": "entity",
"@assert.unique.slug": [
Expand Down
1 change: 1 addition & 0 deletions db/persistence.cds
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ annotate ims.CatGameAwards with @cds.persistence.journal; // #2042 Hit-the-Cat
// #805 — Observability
annotate ims.MetricSnapshots with @cds.persistence.journal;
annotate ims.PublishTimings with @cds.persistence.journal;
annotate ims.TutorialValidationRules with @cds.persistence.journal;
20 changes: 20 additions & 0 deletions db/schema.cds
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,9 @@ entity TutorialContributors : cuid, LegacyKeyed {
name : String(255);
email : String(255);
role : String(50);
login : String(255); // GitHub handle
avatarUrl : String(1024); // https://github.com/<login>.png
profileUrl : String(1024); // https://github.com/<login>
user : Association to Users;
}

Expand Down Expand Up @@ -872,6 +875,23 @@ entity ValidateAnswerSpecs : managed {
aiGrading : Boolean default false;
}

// Full parsed rules.vr rule set for a tutorial, persisted at publish time.
// Unlike ValidateAnswerSpecs (AI-graded only), this holds ALL rule types so
// the admin Validation Questions facet can display the complete rule set.
// options and correctAnswer are JSON-serialised; null when not applicable.
entity TutorialValidationRules {
key tutorial : Association to Tutorials;
key stepNumber : Integer;
key questionId : String(100);
questionText : String(2000);
ruleType : String(50); // single-choice | multiple-choice | regex | exact-match | ...
questionType : String(20); // MCQ | TEXT
choiceMode : String(20); // single | multiple | null
options : LargeString; // JSON array of option strings (MCQ) or null
correctAnswer: LargeString; // reference answer (client-graded) or null when aiGrading
aiGrading : Boolean default false;
}

// Every learner submission. Drives offline grader-quality evaluation.
// 'verdict' allows 'error' as a server-side outcome value (the LLM JSON
// schema only emits 'pass' | 'partial' | 'fail').
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
== version=2
== version=3
COLUMN TABLE com_sap_developers_ims_TutorialContributors (
ID NVARCHAR(36) NOT NULL,
legacyId INTEGER,
tutorial_ID NVARCHAR(36),
name NVARCHAR(255),
email NVARCHAR(255),
role NVARCHAR(50),
login NVARCHAR(255),
avatarUrl NVARCHAR(1024),
profileUrl NVARCHAR(1024),
user_ID NVARCHAR(36),
PRIMARY KEY(ID)
)

== migration=3
-- generated by cds-compiler version 7.0.1
ALTER TABLE com_sap_developers_ims_TutorialContributors ADD (login NVARCHAR(255), avatarUrl NVARCHAR(1024), profileUrl NVARCHAR(1024));

== migration=2
-- generated by cds-compiler version 6.9.0
ALTER TABLE com_sap_developers_ims_TutorialContributors ADD (user_ID NVARCHAR(36));
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
== version=1
COLUMN TABLE com_sap_developers_ims_TutorialValidationRules (
tutorial_ID NVARCHAR(36) NOT NULL,
stepNumber INTEGER NOT NULL,
questionId NVARCHAR(100) NOT NULL,
questionText NVARCHAR(2000),
ruleType NVARCHAR(50),
questionType NVARCHAR(20),
choiceMode NVARCHAR(20),
options NCLOB,
correctAnswer NCLOB,
aiGrading BOOLEAN DEFAULT FALSE,
PRIMARY KEY(tutorial_ID, stepNumber, questionId)
)
Loading
Loading