Skip to content

Developer Portal Homepage Architecture โ€‹

The homepage redesign (issue #639) replaces developers.sap.com/ with a new top-level developer gateway. This document covers the platform engineering view: data model, services, build-time data feeds, runtime endpoints, and operational handles.

Spec: docs/superpowers/specs/2026-06-27-639-developer-homepage-design.mdPlan: docs/superpowers/plans/2026-06-27-639-developer-homepage.md


Components โ€‹

LayerComponentSource
Data modelHomepageShelves entity + admin Fiori appdb/homepage.cds, app/admin-annotations.cds
Data modelLegacyRedirects entity + admin Fiori appdb/homepage.cds, app/admin-annotations.cds
Data modelHomepageConfig singleton + admin Fiori appdb/homepage.cds, app/admin-annotations.cds
ServiceHomepageService (@path: /api/homepage)srv/homepage-service.cds, srv/homepage-service.js
Build feedHomepageShelvesEndpoint (GET /build/homepage-shelves)srv/developer-service.js
FetcherYouTube fetcher (srv/lib/youtube-fetcher.js)Calls YouTube Data API v3
FetcherRSS fetcher (srv/lib/homepage-rss-fetcher.js)SAP Community blogs + SAP News RSS
MergerEvents merger (srv/lib/homepage-events-merger.js)Merges DB events + events calendar
ResolverLegacy-redirects resolver (srv/lib/legacy-redirects-resolver.js)Loads LegacyRedirects from DB, refreshes hourly
ApprouterLoader + hit counter (approuter/lib/)Loads redirectsActive at startup, records POST /api/homepage/recordRedirectHits
CronLink-health job (srv/jobs/homepage-link-health.js)Nightly 04:00; updates HomepageShelves.linkStatus
CronReshuffle video rotation (srv/jobs/reshuffle-video-rotation.js)Every 4h @ :19; ranks ext.Videos by view velocity into HomepageVideoRotation

Page Anatomy โ€‹

Seven rows top-to-bottom on the homepage. Each verb also has a dedicated sub-page at /<verb>/:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Row 1 ยท Hero                                                         โ”‚
โ”‚   One short sentence. No CTAs, no search bar, no campaign slogan.   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 2 ยท Verb spine                                                   โ”‚
โ”‚   Six tiles: Learn ยท Build ยท Integrate ยท Operate ยท AI ยท Connect.    โ”‚
โ”‚   Each tile previews the Start Here shelf + links to /<verb>/.       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 3 ยท Events band                                                  โ”‚
โ”‚   6 upcoming events, auto-pulled from CommunityEvents, region-      โ”‚
โ”‚   filtered per user preference. Runtime: /homepage/events (60s      โ”‚
โ”‚   per-key cache; flag: HomepageConfig.eventsBandAutoPullEnabled).   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 4 ยท SAPDevs video band                                           โ”‚
โ”‚   LEFT โ€” Weekly Developer News. RIGHT โ€” up to 6 tiles: 3 newest      โ”‚
โ”‚   (anchors) + 3 popular (rotation, every 4h). #1031                  โ”‚
โ”‚   Runtime: /api/homepage/videos (15-min cache; YouTube Data API v3). โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 5 ยท Featured missions carousel (topic-based, 8 slides ร— 4 missions)    โ”‚
โ”‚   KG-driven topic slides with editorial override. SSR baseline:     โ”‚
โ”‚   hugo/data/featured_topics.json. Runtime: /homepage/featuredTopics.โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 6 ยท Community lane                                               โ”‚
โ”‚   Columns: Developer Advocates ยท Community blogs ยท SAP News.         โ”‚
โ”‚   Runtime: /api/advocates + /api/homepage/communityBlogs +          โ”‚
โ”‚            /api/homepage/news (30-min cache for feeds).              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Row 7 ยท Comprehensive directory footer                               โ”‚
โ”‚   6 columns (one per verb). All 50+ destinations grouped by verb.   โ”‚
โ”‚   Build-time: hugo/data/homepage_shelves.json.                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Verb Sub-Page Contract โ€‹

Each verb sub-page at /<verb>/ renders all HomepageShelves entries for that verb, organized into four named shelves:

Shelf keyPurpose
START_HERE1-3 marquee entry points; admin-curated
REFERENCECanonical docs and APIs; admin-curated
TOOLSIDEs, SDKs, GitHub org links; admin-curated
KEEP_CURRENTVideos, community, news for this verb; mixed curated + live

Three verb sub-pages carry an extra section beyond the four shelves:

Sub-pageExtra section
/learn/Curated learning paths (missions / learning journeys)
/operate/BTP service catalog teaser (Discovery Center feed)
/connect/Events calendar (full upcoming event list)

Data Flow โ€‹

RowData sourceFreshness mechanism
Row 1 heroStatic (Hugo front matter)Rebuild only
Row 2 verb spinehugo/data/homepage_shelves.json (baked from GET /build/homepage-shelves)Rebuild on admin HomepageShelves save (debounced 60s dispatch)
Row 3 eventsGET /homepage/events?region=<X>&includeVirtual=<b> โ€” 60s per-key cache; sourced from CommunityEvents when HomepageConfig.eventsBandAutoPullEnabled=true else legacy Events entity60s per-key server-side cache
Row 4 videosGET /api/homepage/videos15-min server-side cache; depends on YOUTUBE_API_KEY
Row 5 featured carouselhugo/data/featured_topics.json (baked by scripts/fetch-featured-topics.ts) + runtime /homepage/featuredTopicsNightly job at 04:13 UTC (kg-featured-topics-job) + editorial-save debounced rebuild (60s)
Row 6 community/api/advocates + GET /api/homepage/communityBlogs + GET /api/homepage/newsAdvocates: 60s + SWR; RSS feeds: 30-min cache
Row 7 directory footerhugo/data/homepage_shelves.jsonSame as Row 2

homepage_shelves.json is generated during build:all by fetching GET /build/homepage-shelves from the CAP backend (same pattern as /build/catalog for missions). This bakes shelf content into the Hugo build so the directory footer and verb-spine previews work without a runtime API call.


URL Contract โ€‹

New URLs (spec ยง9.1) โ€‹

URLServes
/New developer-portal homepage
/learn/Learn verb sub-page
/build/Build verb sub-page
/integrate/Integrate verb sub-page
/operate/Operate verb sub-page
/ai/Extend-with-AI verb sub-page
/connect/Connect verb sub-page
/tutorial-navigator/Relocated tutorial navigator (was /)

Legacy Redirects (spec ยง9.3) โ€‹

Managed via the LegacyRedirects CDS entity. The approuter middleware (approuter/server.js) loads the redirect map at startup from GET /api/homepage/redirectsActive and refreshes hourly. Redirect hits are written back via POST /api/homepage/recordRedirectHits (idempotent batch, approuter-internal).

Legacy URLTargetType
/tutorial-navigator.html/tutorial-navigator/301 named
/index.html/301 named
/topics/<tag>.html/tags/<tag>/301 pattern
/mission.html?id=<id>/missions/<slug>/301 pattern
/group.html?id=<id>/groups/<slug>/301 pattern
/<any>.html/<any>/ (if exists)301 catch-all

Admin Operations โ€‹

Add shelf entry: Open /admin-ui/#homepage, Shelves tab, press Create. Set verb, shelf, title, url, and optionally description, badge, sortOrder. Save triggers a rebuild dispatch (60s debounce) so the change appears in hugo/data/homepage_shelves.json within ~2 minutes.

Add legacy redirect: Open /admin-ui/#homepage, Redirects tab, press Create. Set fromPath, toPath, statusCode (301 default), and optionally isPattern. The approuter middleware picks up changes on its next hourly refresh โ€” no redeploy needed.

Update YouTube playlist ID: Open /admin-ui/#homepage, Config tab, edit developerNewsPlaylistId (the YouTube playlist ID for the featured Developer News series). The 15-minute video cache expires automatically; no restart needed.

Nightly link-health: The homepage-link-health cron job (04:00 daily) sends HEAD requests to every active HomepageShelves.url and writes linkStatus (OK | SLOW | BROKEN) + lastChecked back to the entity. Broken links surface as a red dot on the Shelves tab in the admin UI. Threshold for SLOW is 1500ms (default); timeout is 5000ms per URL; concurrency is 4 with 200ms between requests.


Explainer popovers โ€‹

Issue #759 adds progressive-disclosure explainers to the homepage verb spine, the directory footer, and the verb sub-page link cards. The data model (VerbDefinitions, ShelfDefinitions, plus three new fields on HomepageShelves), build feeds, AI-generation actions, Vue islands, and admin workflow are documented separately to keep this file focused.

See Homepage explainer popovers for:

  • Data model (3 entities + the AuthoringStatus lifecycle)
  • New build feeds (/build/verb-definitions, /build/shelf-definitions)
  • AI-generation actions on AdminService and the AICORE_EXPLAINER_GENERATOR_DISABLED kill switch
  • Vue islands (verb-flip-tile, link-explainer-popover) and their Hugo attach points
  • Admin UI surfaces under /admin-ui/#verb-definitions, /admin-ui/#shelf-definitions, and the Explainer facet on the Homepage Shelves Object Page
  • Authoring workflow for new BTP environments

Row 5 of the homepage was previously a static tutorials-catalog teaser. Issue #1032 replaces it with a KG-driven topic carousel: up to 8 slides, each showing up to 4 mission cards for a concept ranked by the nightly PageRank job.

Data flow: The nightly kg-featured-topics-job (04:13 UTC) calls recomputeSnapshot, which joins ConceptRank ร— HomepageFeaturedTopics editorial rows ร— KgCommunity diversity filter, then materialises the result into FeaturedTopicsSnapshot. scripts/fetch-featured-topics.ts reads the snapshot via GET /build/featured-topics and writes hugo/data/featured_topics.json for SSR. At runtime, the Vue island (hugo-apps/src/featured-topics-carousel/) re-hydrates via GET /homepage/featuredTopics() with weak ETag / 304 caching.

Admin surface: /admin-ui/#featured-topics โ€” FeaturedTopics CRUD + manual recomputeFeaturedTopics action (SuperAdmin-gated).

Kill switch: revert the Row 5 Hugo partial include (hugo/layouts/partials/homepage/featured-topics-carousel.html) to restore the previous teaser โ€” no DB migration needed.

Spec: docs/superpowers/specs/2026-07-06-1032-featured-missions-carousel-design.mdPlan: docs/superpowers/plans/2026-07-06-1032-featured-missions-carousel.md


SAP News (developer-relevance filter โ€” #1034) โ€‹

The homepage /homepage/news handler serves items from the NewsItems HANA table when the two-layer kill switch is on. srv/jobs/fetch-news-job.js runs hourly (:37) against news.sap.com/feed/; each item is classified by srv/lib/relevance-classifier.js (embedding-first via RelevanceSeedExemplars, LLM fallback for the mid-band, keyword rules on any error).

Admins triage at /admin-ui/#content-moderation โ€” approve, reject, clear override, or reclassify a single item. Admin verdicts win over AI at read time. Homepage items are capped at 2, aged out after 14 days, English-only.

Kill switches (either off โ†’ legacy RSS pass-through):

  • Env HOMEPAGE_NEWS_RELEVANCE_ENABLED (default: unset; only the literal string false disables โ€” any other value, or absence, treats as enabled).
  • HomepageConfig.newsRelevanceEnabled (default false).

Community Blog Posts (#1033) mirrors this pattern using the same ContentModerationService + RelevanceSeedExemplars shared seed set.


Personalization for signed-in users โ€‹

Issue #763 adds per-user reordering + filtering + a "For you" row. See homepage-personalization.md for:

  • Endpoint contract + ETag/304 + X-Personalization: 1 marker
  • Persona-tag admin workflow
  • BroadcastChannel live re-render + ?default=1 bypass
  • Kill switch (HomepageConfig.personalizationEnabled)

Failure Modes โ€‹

FailureBehaviour
YouTube API 403 or timeoutVideo band renders a static link card to @sapdevs YouTube channel. No crash.
Community blogs / SAP News RSS 4xx or network errorEmpty column with a direct link to community.sap.com / news.sap.com. No crash.
Events DB unavailableEvents band renders empty. No crash.
HomepageShelves link-health BROKENRed indicator on admin Shelves tab only. No user-facing impact (links still render; admins decide whether to disable).
Approuter โ†’ srv unavailable at startupLegacy-redirects resolver skips load and logs a warning; middleware retries on the next request. No boot crash.
HomepageConfig missingAdmin auto-init handler creates the singleton on first READ with safe defaults (videoBandEnabled: true, eventsBandEnabled: true, communityLaneEnabled: true). Consistent with the pattern used by ChatSettings, DisplaySettings, etc.
YOUTUBE_API_KEY not setyoutube-fetcher.js returns an empty array; video band degrades gracefully to the static link card.
Reshuffle cron throwsHomepageVideoRotation untouched (single-tx ROLLBACK). Stale rotation continues to serve.
HomepageVideoRotation empty (fresh deploy)Response returns anchors only; client renders 3 tiles until first cron pass.
Statistics fetch fails in fetch-videos-jobSnippet upsert already succeeded; view/like counts stay stale. Rotation deprioritises null-viewCount rows to bottom.

Site Integration โ€‹

The new pages live inside the same Hugo site shell as the rest of developers.sap.com. Header (<ui5-shellbar>), footer, Joule panel, alerts popover, command palette, cookies banner, and theme switcher all render unchanged via hugo/layouts/_default/baseof.html.

Page-kind dispatch drives per-page Joule starters + behaviour. baseof.html writes data-page-kind="..." on <html>:

Pagedata-page-kind
/homepage
/learn/verb-learn
/build/verb-build
/integrate/verb-integrate
/operate/verb-operate
/ai/verb-ai
/connect/verb-connect
/tutorial-navigator/tutorial-navigator
/tutorials/<slug>/tutorial (unchanged)

Joule starters per page-kind live in hugo/layouts/partials/joule-starters.html. The new homepage's set is concierge-shaped โ€” "where can I find โ€ฆ?" prompts that nudge users toward the right destination in the SAP developer landscape. Per-verb sets nudge deeper into each lane.

Navigate popover (hugo/layouts/partials/header.html) was reorganised on the cutover to surface the new lanes: Home โ†’ 6 verb pages โ†’ Tutorial navigator โ†’ existing sub-pages (App Space, Event Display, Devtoberfest, Developer Advocates) โ†’ conditional Me / Admin UI.

Deferred enhancement โ€” Joule chat handler routes to catalog โ€‹

The current implementation provides discovery-shaped starter prompts but the underlying Joule chat handler (srv/chat-service.js + srv/lib/chat-orchestrator.js) is the same tutorial-RAG handler used elsewhere on the site. It can answer "where can I find SAP BTP AI best practices?" reasonably because BTP-AI Best Practices is in the tutorial corpus, but it has no first-class knowledge of the HomepageShelves catalog.

A future enhancement would teach the chat orchestrator to call /api/homepage/shelves?verb=<v> and /api/homepage/redirectsActive, treating the catalog rows as first-class retrieval sources alongside tutorial content. On a homepage or verb-<key> page-kind, the handler would prioritise catalog-shelf citations over tutorial-step citations and link out to the appropriate destination URL.

That work is out of scope for issue #639 and lives as a future follow-up. The infrastructure (catalog data + endpoint + admin-curated content) is already in place.


CodeJams auto-pull (#1030) โ€‹

Issue #1030 rewrites Row 3 (events band) to pull from CommunityEvents automatically and adds per-user region preference.

Spec: docs/superpowers/specs/2026-07-07-1030-homepage-codejams-autopull-design.mdPlan: docs/superpowers/plans/2026-07-07-1030-homepage-codejams-autopull.md


Video band rotation (#1031) โ€‹

Row 4's right stack expands from 3 to 6 tiles (configurable via HomepageConfig.videoBandAnchorCount + videoBandRotationCount). Anchors always show the most recently published videos; the rotation slot set is materialised into HomepageVideoRotation every 4h by srv/jobs/reshuffle-video-rotation.js, ranked by view velocity (views per day since publishedAt) over the trailing videoBandRotationWindowDays (default 90).

Admin surfaces:

  • /admin-ui/#videos โ€” toggle excludeFromHomepage per video; manual recomputeHomepageVideoRotation action (SuperAdmin-gated).
  • /admin-ui/#video-rotation โ€” read-only view of the current rotation.
  • /admin-ui/#homepageConfig โ€” tuning knobs.

Kill switches:

  1. videoBandRotationCount = 0 โ†’ anchor-only (existing 3-tile behaviour). Zero deploy.
  2. videoBandEnabled = false โ†’ whole band disabled (unchanged from before).