feat: add CAP search service with HANA fuzzy search - #3
Merged
Merged
Conversation
Addresses all review findings: - Add AppRouter /search/ route (deployment requirement) - Fix tag-search to use before READ handler (correct pagination) - Move @Search.fuzzinessThreshold to service entity - Document nullable slug contract for GROUP results - Use named types for getFacets return (OData serialization) - Add risk callout for CONTAINS on UNION view - Filter view to active-status items only
Add comprehensive Frontend Integration section covering: - TutorialNavigator.vue rewrite from client-side to server-side search - useSearch.ts composable for extracted search logic - SearchableItem/SearchFacets TypeScript interfaces - OData $filter mapping from UI filters - Server-side pagination ($top/$skip/$count) - Progressive enhancement strategy (Phase 1: server search + local filters) - UX behavior changes and filter panel population from Tags entity
Replace the phased migration approach with a permanent hybrid model: - Browse mode (no search term): fully client-side, same as today - Search mode (2+ chars): server-side via OData with fuzzy matching This preserves instant filter toggles while adding fuzzy search quality.
3 tasks
jung-thomas
added a commit
that referenced
this pull request
May 29, 2026
…it (#70) Tom retested DEV after a17db86 (fix attempt #3 for issue #70) — drag still does nothing, items still snap back. Network and console panels showed the real story this time: * Console (with verbose enabled): zero `ItemReorder:` warn/error output — the defensive logs added in a17db86 never fire. * Network panel filtered for 'ItemReorder': no row appears anywhere across a full page lifecycle. The handler module was never being fetched. `drop="handler.onDrop"` resolves against an undefined alias, so it's a silent no-op and the only thing the user sees is the row-rebind on activation that looks like a snap-back. Root cause: the file was named `ItemReorder.controller.js` (module ID `sap/tutorials/admin/groups/ext/ItemReorder.controller`). FE V4 reserves the `*.controller.js` path for its controller-extension machinery, and a `core:require` pointing at that module ID resolves to undefined silently — no console error, no network 404 visible in DevTools. The working sibling next door is `TaskColumnHandler.js` (no `.controller` suffix), which is why the cell-edit input on the Mission Tasks table works fine. Three previous fixes (#86, #94, a17db86) all edited the body of `onDrop` on theories that assumed the handler ran. None of them did. This commit is deliberately scoped to the rename + `core:require` update only — the body of the handler (including the `%{IsActiveEntity}` gate, defensive active-row check, and refresh sequence from a17db86) is untouched, so once it actually loads, the existing logic gets its first real test. Files: * `app/admin/groups/webapp/ext/ItemReorder.controller.js` → `app/admin/groups/webapp/ext/ItemReorderHandler.js` * `app/admin/missions/webapp/ext/ItemReorder.controller.js` → `app/admin/missions/webapp/ext/ItemReorderHandler.js` * Both `ItemReorder.fragment.xml` files updated to the new module ID. The `ItemReorder.fragment.xml` filenames stay the same — `manifest.json` references the section as `sap.tutorials.admin.{groups,missions}.ext.ItemReorder` (fragment), which is independent of the handler module ID. Closes #70
jung-thomas
added a commit
that referenced
this pull request
Jun 2, 2026
Phase-by-phase TDD plan covering issue #171 capability #3 (code-check) per the spec at docs/superpowers/specs/2026-06-02-ai-code-check-spike-design.md. - Phase 1 (Tasks 1.1-1.9): backend foundation behind a flag. Schema, parser, prompt builder, dispatch core, Express endpoint with rate limits, real LLM via forced tool-call, publish endpoint, Joule chat tool registration. - Phase 2 (Tasks 2.1-2.4): publish CLI extension, Hugo mount, frontend island, @analytics.exposed. - Phase 3 (Tasks 3.1-3.3): hybrid + smoke + manual eval harness. - Phase 4 (Tasks 4.1-4.2): aggregate evidence, decide, comment on issue. Cross-cutting concerns covered: security, CAP 10 readiness, Windows CRLF, Hugo gotchas, srv-qa cp list audit, branch hygiene, CLAUDE.md update. Refs #171
This was referenced Jun 5, 2026
Merged
jung-thomas
added a commit
that referenced
this pull request
Jun 19, 2026
* docs(spec): #394 disable change tracking during migration design Spec for issue #394: REST migrators (migrate-reference-data.js, migrate-user-progress.js) currently POST to /admin/<Entity> and trip @cap-js/change-tracking, polluting sap.changelog.Changes with thousands of bogus migration entries. Approach: opt-in 'x-migration-mode: true' request header honored only when req.user.is('admin'). Sets the same 'ct.skip' session variable that the plugin already reads. Self-cleaning per request; no global toggle to forget. * docs(spec): #394 spec rev 2 — incorporate spec-review feedback Reviewer caught multiple issues: - Blocker: role is 'Admin' (capital A), not 'admin' - Blocker: migrate-from-hana DOES trip change-tracking on HANA (DB-level AFTER INSERT/UPDATE/DELETE triggers fire regardless of whether the write came through CAP). Out-of-scope for #394 but documented in the runbook with operator mitigation. - Major: populateSlugs() PATCH path is also affected and was missed - Major: srv/admin-service.js is ESM with class extends ApplicationService; pseudocode rewritten as ESM - Major: header access via cds.context.http?.req?.headers is the documented stable API - Major: register on cds.db.before(['INSERT','UPDATE','DELETE']) for parity with the plugin's own implementation; req._tx is reliably the DB tx there - Major: migrate-user-progress entities are NOT @changelog-tracked today — header is defense-in-depth, called out - Major: split tests into plugin-contract pin + handler behavior; added hybrid test for HANA SESSION_CONTEXT semantics - Minor: register new docs page in vitepress sidebar - Minor: paired after handler resets ct.skip for pooled connections * docs(spec): #394 spec — align cds.db.before event list (rev 2 nit) Reviewer round-2 minor: spec text alternated between cds.db.before('*') and the explicit ['INSERT','UPDATE','DELETE'] array form. Pick the array form everywhere to match the plugin's own pattern verbatim. Spec verdict: Approved (round 2). * docs(plan): #394 implementation plan 7 tasks: contract pin → handler → migrator headers → hybrid test → docs → manual verification → PR. Bite-sized TDD steps with exact file paths, paste-ready code, and explicit RED→GREEN→COMMIT loops. Plan derived from rev-2 spec at docs/superpowers/specs/2026-06-18-394-disable-change-tracking-during-migration-design.md * docs(plan): #394 plan rev 2 — fix test scaffolding bugs from review Reviewer round 1 caught real defects in the paste-ready code blocks: - cds.test() pattern: project handle from cds.test('serve', ...) with project.url, not invented cds.test.port - Auth: 'admin:admin' (real password from .cdsrc.json), not 'admin:' - Hybrid: named-import isSafeForWrites + describe.runIf gate; previous side-effect import did nothing - Entities API: cds.entities('com.sap.developers.ims') (function call), not bracket index - Contract pin uses Advocates (DB-level @changelog) instead of Missions (AdminService-level) to remove service-vs-DB ambiguity in the test Plan structure unchanged — only paste-ready snippets fixed. * docs(plan): #394 plan rev 3 — drop stale ALLOW_HYBRID_WRITES from success criteria Reviewer round 2 flagged a stale ALLOW_HYBRID_WRITES env-var prefix in the 'What success looks like' section that contradicted the round-1 fix (the actual write gate is isSafeForWrites() in test/hybrid/_guard.js). Other round-2 reviewer notes: - Issue #1 (cds.entities bracket vs function call for sap.changelog.Changes): false-positive. Both forms work in CAP; bracket-by-fully-qualified-name is fine. No change. - Issue #3 (--profile hybrid in cds.test for hybrid suite): false-positive. test/hybrid/admin-crud.test.js uses exactly this pattern. No change. - Issue #4 (branch name mismatch): false-positive. The reviewer was reading the session-start gitStatus header which preceded the worktree creation; the worktree's actual branch matches the plan. * docs(plan): #394 plan revision after Task 1 SQLite-harness blocker Implementer subagent surfaced that: 1. tx.set in cds.tx callback errors on @cap-js/sqlite (no dbc yet) 2. SQLite triggers don't fire in cds.test('serve','--in-memory'), so POST /admin/Missions produces 0 Changes rows even without any suppression — meaning the unit-level end-to-end test is infeasible regardless of what we do with the handler. Tom chose hybrid-only end-to-end coverage. Plan revised: - Drop unit Changes-row assertions - Add unit spy test for req._tx.set routing only - Hybrid test (Task 4) is the sole end-to-end pin - Manual DEV verification (Task 6) gains importance * feat(srv): add migration-mode handler that suppresses change tracking (#394) When an admin-authenticated request carries x-migration-mode: true, sets the @cap-js/change-tracking plugin's ct.skip session variable on the DB tx so changelog triggers no-op. Paired after-handler resets. End-to-end Changes-row verification lives in the hybrid test (test/hybrid/migration-mode.test.js, separate commit) since in-memory SQLite doesn't fire the plugin's triggers. Unit tests here verify only the handler's routing logic via spies. * feat(scripts): send x-migration-mode header from REST migrators (#394) Three header sites: - migrate-reference-data.js importData() POSTs - migrate-reference-data.js populateSlugs() PATCHes (covers both Missions + CompletionPaths via shared headers object) - migrate-user-progress.js importUsers() POSTs (defense-in-depth; current user-progress entities are not @changelog-tracked) * test(hybrid): pin HANA SESSION_CONTEXT('ct.skip') suppression (#394) Verifies the migration-mode handler's session-variable contract on real HANA. Targets AdminService.ImsConfig (element-level @changelog on key/value, not draft-enabled, no extra business validators) so the test exercises the cds.db before('INSERT') hook end-to-end via plain HTTP — no draft round-trip needed. The plan's original target was Advocates, then AdminService.Missions: - Advocates has only entity-level @changelog: true and would not fire the change-tracking triggers (plugin only emits trigger SQL for entities with element-level annotations). - AdminService.Missions has element-level @changelog but is also @odata.draft.enabled and guarded by a Tag-required validator, so driving it via plain HTTP would require draft-then-activate plumbing or bypassing unrelated business rules. ImsConfig is the cleanest exerciser of the actual handler contract. This is the sole end-to-end coverage for #394: in-memory SQLite doesn't fire change-tracking triggers in the cds.test('serve') unit harness, so a regression that breaks header propagation or the SESSION_CONTEXT('ct.skip') write would slip past unit tests. The control test (no header → ≥ 1 new Changes row) proves change tracking IS firing for the same table; without it, the suppression assertion could pass for the wrong reason. * docs(migration): runbook + corrected change-tracking comment (#394) - New /developers/operations/migration-from-ims.md runbook covering reference-data, user-progress, HANA-to-HANA paths + verification - Sidebar registration in docs/.vitepress/config.ts - db/change-tracking.cds header comment corrected (the original claim that DB-level writes are excluded was wrong on HANA — plugin's HANA implementation deploys AFTER triggers that fire on every write) - CLAUDE.md Data Migration section gains a one-line pointer - docs/developers/architecture/hana-kge-access.md: pre-existing Vue parse error and dead link fixed so docs:build succeeds (escape <>/>) --------- Co-authored-by: Thomas Jung <12159356+jung-thomas@users.noreply.github.com>
This was referenced Jun 19, 2026
jung-thomas
added a commit
that referenced
this pull request
Jun 27, 2026
… + edge dedup
Adds a :data-graph-id binding to defeat Vue 3.5 SFC template hoisting
(which made container ref null under @vue/test-utils 2.4.10 + happy-dom
15 — the hoisted vnode warning prevents the ref from being attached).
The binding has no runtime effect; it just signals the compiler to keep
the vnode in the render function.
Test mocks now capture Sigma + graphology instances so:
- Edge dedup is verified by mockGraphInstances[0].edges.size
- The clickNode → emit('nodeClick') path has explicit coverage
Resolves code-review item #3 from PR #687.
jung-thomas
added a commit
that referenced
this pull request
Jul 1, 2026
…reopen) (#876) ## What Riley saw `GET /author/MyAuthoredTutorials` returned 36 tutorials Riley didn't author — Fiori Elements, HANA anonymization, CodeJam entries, AI Core tutorials. Expected: 1 (rbrainey-sandbox-1, his declared authorship). Additionally every row had `ID: undefined` in Sage's log — the projected view's key is `tutorial_ID`, not `ID`. ## Root cause Two compounding issues: 1. **Resolver's Phase (c) `ownerEmail` fallback was architecturally wrong.** `TutorialMeta.ownerEmail` encodes a *monitoring* signal (who watches for staleness), not authorship. The resolver treated it as a last-resort authorship signal, so stale monitoring assignments (from the legacy IMS migration) silently promoted the monitoring user to `Tutorials.author_ID`. On DEV, Riley was `ownerEmail` on 58 tutorials for legacy reasons; 36 of those had no frontmatter author + no matching contributors → Phase (c) fired → author_ID = Riley. 2. **`MyTutorialsView` exposes the tutorial key as `tutorial_ID`, not `ID`.** Sage's `imsApiClient` reads `row.ID` and got `undefined` for every row. The alias was there for the underlying view's naming reasons (#777) but never surfaced to OData clients. Verified against DEV via hana-cli: SELECT COUNT(*) FROM COM_SAP_DEVELOPERS_IMS_TUTORIALS WHERE AUTHOR_ID = '<riley.id>'; → 36 (matches Riley's log exactly) SELECT SLUG, OWNER, OWNEREMAIL FROM COM_SAP_DEVELOPERS_IMS_TUTORIALMETA tm JOIN COM_SAP_DEVELOPERS_IMS_TUTORIALS t ON t.ID = tm.TUTORIAL_ID WHERE t.AUTHOR_ID = '<riley.id>'; → most rows: OWNER = "Bill Jiang" / "Madeline Schaefer" / etc. OWNEREMAIL = riley.rainey@sap.com ← the smoking gun ## Fix (three pieces) ### 1. Remove Phase (c) from `resolveTutorialAuthor` The resolver now stops at Phase 0 (frontmatter) / Phase (a) role-match / Phase (b) any-contributor. If none of those hit, `authorUserId` stays null and the tutorial's `author_ID` is left NULL. The `ownerEmail` parameter is still passed for orphan-CSV reporting (backfill script uses this to surface unresolved rows). Consequence: some tutorials that had `author_ID` set only via the old Phase (c) will end up with `author_ID = NULL` after the next publish cycle. That's correct — they should have been NULL all along. The broader `MyTutorials` endpoint (which reads `MyTutorialsView`, a four-source UNION) still surfaces those tutorials via source #3 (TutorialMeta.ownerEmail = Users.email) so admin Tutorial Health and the advocate roster keep working. Only `MyAuthoredTutorials` (strict authorship) is affected. ### 2. Data repair via `scripts/repair-author-id-phase-c.cjs` One-shot ops script: - Iterates every Tutorial with author_ID IS NOT NULL. - Re-runs the resolver (Phase 0 unavailable — frontmatter isn't persisted on the row, so this is a conservative reproduction). - Three-way classification: ok / conflict / null-out. - `--dry-run` by default; writes `.migration-data/repair-author-id-phase-c-<ts>.csv`. - `--commit` applies UPDATE ... SET author_ID = NULL for the null-out set, gated by WHERE AUTHOR_ID = <current> so concurrent publishes don't get clobbered. - Idempotent (WHERE author_ID IS NOT NULL narrows re-runs to a no-op). - Tutorials whose frontmatter genuinely declares an author will be re-linked on the next publish via Phase 0 (linkTutorialAuthorship overrides on frontmatter hits). No data loss for legitimate cases. Run against DEV after this PR merges: npx cds bind --exec -- node scripts/repair-author-id-phase-c.cjs npx cds bind --exec -- node scripts/repair-author-id-phase-c.cjs --commit ### 3. Alias `tutorial_ID as ID` on both projections `AuthorService.MyTutorials` and `AuthorService.MyAuthoredTutorials` now project `MyTutorialsView { *, tutorial_ID as ID }`. Both aliases coexist on the OData wire so: - Sage's `row.ID` reads correctly (unblocks the Sage panel). - Existing consumers reading `row.tutorial_ID` keep working. ## Tests - `test/unit/resolve-tutorial-author.test.js`: - Retitled the "empty contributors → ownerEmail falls through" case as a **regression guard** that asserts the resolver does NOT elevate ownerEmail. - Replaced "falls through to ownerEmail (Phase B c)" with a mirror assertion that the resolver returns null in that case. - 20/20 tests pass. - `test/unit/author-service.test.js`: - New "exposes tutorial_ID also as ID for OData clients" regression test on `MyAuthoredTutorials`. - 31/31 tests pass. - `test/hybrid/frontmatter-owner.test.js`: - Test 2 flipped from "fallback fill-NULL populates author_ID" to "no-Phase-c: author_ID stays NULL when only ownerEmail matches". - Test 3 updated to reflect the doubly-guarded admin-correction invariant. - `test/hybrid/tutorial-author-backfill.test.js`: - Comment refresh only. seedTriplet already creates a TutorialContributors row with role='author' so Phase (a) matches; the test never depended on Phase (c). Comment corrected. Note: the failing test in `admin-shell-explainer-registration.test.js` is pre-existing on main (verified via stash+rerun) and unrelated to this fix. ## Not in this PR - Sage-side switch to read `row.ID` (no change needed — Sage already reads it; this PR makes the field non-undefined). - Cleanup of the 58 `TutorialMeta.ownerEmail = riley.rainey@sap.com` rows themselves. Those are monitoring assignments; whether they're actually Riley's responsibility is a separate ops question. - Fixing the same class of issue (ownership vs authorship confusion) in other consumers. This PR is scoped to the resolver and the two projections most immediately affected. Closes #862. Co-authored-by: Thomas Jung <12159356+jung-thomas@users.noreply.github.com>
This was referenced Jul 1, 2026
jung-thomas
added a commit
that referenced
this pull request
Jul 9, 2026
… band + blogs bootstrap (#1116) * fix(homepage): 4-way demo bundle — events unwrap, for-you cards, carousel band, blogs bootstrap Bundled fixes for four homepage issues visible on DEV. **#1 Events band — cards not rendering** homepage-events-band/EventsBand.vue read `await resp.json()` and assigned the entire OData envelope `{@odata.context, value:[...]}` to `rows`. Iterating an object with v-for never produced .event-card children, so the empty-state fallback rendered instead. Unwrap `body.value` with a bare-array fallback so fixtures + non-OData mounts still work. **#2 For-you row — no cards, no header, vertical stack, top gap** The Hugo partial only emitted a screen-reader-only <h2>, the section had no hp-band wrapper, and the Vue component emitted a plain <ul><li><a> with zero CSS. Result: browser-default list of links between two padded bands, and a 200px min-height reservation added visible whitespace even when the row was hidden. This change: - Wraps the section in `hp-band`, adds visible "Recommended for you" <h2> plus a "Because you're a <role> <deployment> on <cloud>" explainer chip populated from the personalization envelope. - Rewrites for-you-row.vue to emit `.for-you-card` anchors with thumb, kind pill, title, and 2-line description. - Adds `.for-you-cards.cards` grid CSS matching the tutorials-teaser and featured-carousel grammar (4 → 3 → 2 → 1 columns). - Drops the `min-height: 200px` reservation — coordinator hides the section entirely when there's no data. - mount-for-you.ts now populates the because-chip from the session-cached envelope profile and mounts cards into a dedicated child so the header survives Vue's innerHTML replace. **#3 Featured missions carousel — no background, slow rotate** Section used `.hp-featured-carousel` alone, missing the shared `.hp-band` padding + background that the events, videos, and community sections use. Added `hp-band` to the class list. Also dropped the 30-second auto-advance interval to 8 s so the demo actually shows rotation — `prefers-reduced-motion` still pauses it for a11y. **#4 Community Blog Posts — empty column with just a fallback link** CommunityBlogPosts is empty in DEV: the community-blogs-fetch cron ran successfully but the SAP Community RSS endpoints return Cloudflare 403 to CF outbound IPs, so every source erros and inserts zero rows. JobLastRun still records LASTSUCCESSAT because the job returns instead of throwing. - Fail-loud: runCommunityBlogsFetch now throws when `errored >= sources` so the cron chassis populates LASTERRORAT + LASTERRORMESSAGE, and the admin Cron health tile surfaces the outage. - DEV bootstrap: 4 admin-pinned rows seeded directly in HANA (`ID = 11111111-1111-1111-1111-00000000000{1..4}`, `adminOverride='ALLOW'`, `pinned=true`, `aiVerdict='DEVELOPER_RELEVANT'`) so the column renders content immediately. Not part of this diff — SQL applied directly to DEV HANA. The Community Blogs admin UI at `/admin-ui/#homepage/blog-posts` can curate them post-demo. **Test note** EventsBand.test.ts has 3 pre-existing failing tests (verified by stashing this branch and running on main — same failures). Root cause is Vue-test-utils / happy-dom timing: `onMounted → await refetch` leaves `loading = true` after one microtask. Added a new OData-envelope regression test in the same shape as the existing broken tests so it covers the fix but doesn't force a separate rewrite of the whole suite. Follow-up issue owed. Verified live on DEV: - Homepage HTML contains hp-band wrappers + Recommended-for-you header. - /homepage/communityBlogs → 3 pinned rows. - /homepage/events?region=ALL → 6 cards. * fix(homepage): round 2 — event card visual chrome, gap, featured header Follow-up fixes on top of the initial demo bundle (previous commit 0ee75d4). Three issues Tom flagged after the first deploy: **Event cards — no visual chrome.** `.event-card` had CSS defined in `hugo/assets/css/homepage/_events-band.css` but that file was hooked in via a raw `@import` statement in `homepage.css`, which Hugo's `resources.Get` pipeline emits as-is (no postcss). Browsers dutifully fetched `/css/homepage/_events-band.css` and got a 404 — Hugo doesn't publish partial CSS files as static assets. Result: 6 zero-border, zero-background, zero-padding stacked text divs since #1030 shipped. Fix: inlined the events-band chunk into `homepage.css` directly. Original partial kept as source-of-truth for future edits (documented in the inline comment). Refreshed the card look while I was there: softer border, 8px radius, hover lift + shadow, chip-style event type badge, meta row separated by top-border. **Gap between verb spine and events band.** `.developer-homepage` used `gap: 3rem` (48 px) which combined with the two hp-band's own 1.5 rem padding felt cavernous. Tightened to `gap: 2rem` (32 px). **Featured missions header disappearing on hydration.** Vue mounts `Carousel` directly on the `<section>` — `createApp(...).mount(el)` replaces `el.innerHTML` wholesale, so the SSR-emitted `<div class="hp-featured-carousel__header"><h2>Featured missions</h2>" …</div>` was wiped on first hydration tick. Users only saw the Vue-rendered slide title ("SAP BTP Cockpit Navigation" etc.), never the section title. Fix: refactored `main.ts` to mount into a dedicated `[data-vue-root]` child element inserted after the SSR header. The `root` prop still points at the `<section>` so `useAutoAdvance`'s hover/focus listeners and the `.hp-featured-carousel--pending` toggle still work as before. Verified live on DEV after redeploy: - event-card computed border 0.8 px solid, bg #fff, padding 16 px, border-radius 8 px, display flex — actual cards. - .hp-featured-carousel__header + <h2>Featured missions</h2> present in mounted DOM. - verb-spine → events-band gap = 32 px (was 48 px). --------- Co-authored-by: Thomas Jung <12159356+jung-thomas@users.noreply.github.com>
This was referenced Aug 4, 2026
This was referenced Aug 20, 2026
This was referenced Sep 12, 2026
This was referenced Sep 17, 2026
6 tasks done
jung-thomas
added a commit
that referenced
this pull request
Sep 17, 2026
All-day activities (Developer Garage, AI Showfloor Expo, etc.) live under a SEPARATE RainFocus catalog tab (`tab.alldayactivities=<id>`), NOT in the regular `type=session` feed. This PR wires them in end-to-end. **Model** (`db/external/teched.cds`) - Add `allDay Boolean default false` to `TechEdSessions`. **Fetcher** (`srv/lib/teched/rainfocus-fetcher.js`) - New `parseAllDayActivity(item, venue)` — lenient parser (synthesises `allday-<sourceId>` code when absent, room from `location`/`venue` fallback, `allDay: true`). - `fetchAllTechEdSessions` issues a best-effort per-venue all-day POST (own try/catch; `allDayFilter` env-configurable; empty ⇒ skipped). - `parseVenuePayload` accepts `allDayItems`; dedup via `seenSourceIds` (regular session wins on collision). - `dropPast` never drops a row where `s.allDay === true`. - Defaults: Berlin filter `1742815606768001gh9v` (Tom's capture), Virtual unset; tab param `tab.alldayactivities`. **Normalize** (`srv/lib/teched/normalize.js`) - `normalizeSession` maps `allDay: raw.allDay === true` (part of hash). **Seed** (`srv/lib/teched/seed-core.js`) - `SESSION_COLS` includes `'allDay'`. **Feed** (`srv/lib/teched-feed.js`) - SELECT includes `allDay`; emits `allDay: isAllDay(r.allDay)`. - Shared `isAllDay(v)` helper (coerces `true`/`1` → boolean). - `upcoming=true` filter uses tagged-template CQL (safe ISO binding) with explicit `OR allDay = true OR scheduledEnd is null` carve-out so timeless all-day rows survive the filter. **UI** (`hugo-apps/src/teched-sessions-grid/App.vue`, `filter.ts`) - `allDay?: boolean` on `TechEdSession` interface. - `filteredAllDay` / `filteredTimed` computed splits. - Distinct `<section aria-label="All-day activities">` with "All-day" badge rendered above the timed grid; timed grid unaffected. - `test/unit/teched-allday.test.js` — parseAllDayActivity, dedup, fetchAllTechEdSessions all-day tab, normalizeSession allDay flag. - `test/unit/srv/build-teched-allday.test.js` — allDay flows through seed → /build/teched; upcoming filter keeps all-day rows. - `hugo-apps/src/teched-sessions-grid/__tests__/App.allday.test.ts` — all-day section renders, excluded from timed grid, badge, detail panel, filter across both sections. - `test/unit/teched-normalize.test.js` — allDay flag coverage extended. - `test/fixtures/teched/rainfocus-alldayactivities.json` — synthetic raw all-day tab capture (live params unconfirmed — see OPEN ITEM). - `test/fixtures/teched/teched-allday-feed.json` — derived feed shape. The exact live RainFocus request param name/value for the all-day tab is NOT yet confirmed against the real API. Parsing, model, seed, feed, and UI are proven against the synthetic fixture. Tune `RAINFOCUS_TE26_ALLDAY_FILTER` / `RAINFOCUS_ALLDAY_TAB_PARAM` when a live capture is available — a mismatch yields 0 all-day rows and never breaks the regular session ingest. - #2 iCal all-day gap: graceful 404 out of scope for this unit. - #3 NULL-first ordering on SQLite vs HANA: catalog << 1000 cap, latent. - #5/#6 UI/parser duplication: deliberate (scoped CSS + tested parseSession). - #7 mass UPDATE on first ingest: one-time benign, expected behaviour.
This was referenced Sep 22, 2026
Open
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SearchServiceat/search(unauthenticated) replacing AEM's Solr-backed/bin/ims/searchendpointSearchableItemsUNION view across Tutorials, Missions, and Groups (active only)CONTAINS()withFUZZY(0.7)for typo-tolerant search and@Search.rankingannotations for field-weighted relevancebefore READhandler augments results with tag-matched tutorials (OR expansion)getFacetsfunction returns aggregated counts by type, experience, and taguseSearchVue 3 composable with debounced server-side search, integrated intoTutorialNavigator.vueas hybrid browse/search modeTest plan
npm testnpm run build:appsnpm run test:hybridto validate HANA fuzzy search and{ and: [...] }CQL (requirescf login)npm run test:smoketo verify end-to-end