Skip to content

Conversation

@aka4rKO
Copy link

@aka4rKO aka4rKO commented Nov 24, 2025

Purpose

$subject

Summary by CodeRabbit

  • New Features

    • Added dual data-source support: dashboard can now use either Moesif Analytics (default) or OpenSearch as the data backend.
    • Implemented configurable data-source selection via environment variables.
  • Documentation

    • Updated README with comprehensive setup guides for both Moesif Analytics and OpenSearch paths.
    • Added instructions for switching between data sources and configuration examples.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

Walkthrough

This PR introduces dual data-source support to the dashboard, enabling runtime selection between OpenSearch and Moesif Analytics via configuration flags. A new MoesifService class provides data retrieval and analytics capabilities, while the dashboard controller routes requests conditionally based on the selected source.

Changes

Cohort / File(s) Summary
Build Configuration
.gitignore
Added ignore entries for macOS (.DS_Store) and JetBrains IDE (.idea/) configuration files
Documentation
dashboard/README.md
Expanded README to document dual data-source workflow, replacing single-source setup with configurable Moesif Analytics (default) and OpenSearch paths. Added Data Source Selection section, expanded Quick Start with two setup options, detailed configuration and deployment for both sources, and switching instructions
Environment Configuration
dashboard/swift_dashboard/server/.env.example
Added USE_OPENSEARCH toggle and new block of Moesif integration environment variables (API keys, search path, base URL, timeouts, retry settings, cache TTL)
Data Source Routing
dashboard/swift_dashboard/server/controllers/dashboardController.ts
Introduced runtime USE_OPENSEARCH flag to conditionally select data source. Added MoesifService dependency and optional openSearchService field. Constructor reads env flag and conditionally initializes services. Updated all data-fetching methods with conditional branches routing to OpenSearch or Moesif based on flag
New Moesif Integration Service
dashboard/swift_dashboard/server/services/moesifService.ts
Introduced comprehensive MoesifService class with configurable Moesif API client, retry semantics, caching, and data retrieval utilities. Includes methods for fetching messages by date range, chart data aggregation (daily/weekly/monthly), error statistics, message type analytics, and cache management

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as DashboardController
    participant Config as Environment
    participant OpenSearch as OpenSearchService
    participant Moesif as MoesifService

    Client->>Controller: Request data (e.g., getMessages)
    Controller->>Config: Read USE_OPENSEARCH flag
    
    alt OpenSearch enabled (USE_OPENSEARCH=true)
        Controller->>OpenSearch: Call openSearchService method
        OpenSearch-->>Controller: Return data
    else Moesif (default)
        Controller->>Moesif: Call moesifService method
        Moesif-->>Controller: Return data
    end
    
    Controller-->>Client: Return response
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • dashboard/swift_dashboard/server/services/moesifService.ts: New 400+ line service with extensive API client setup, retry logic, caching, and 15+ public methods. Requires careful review of retry strategy, request/response interceptors, query building logic, and data mapping functions.
  • dashboard/swift_dashboard/server/controllers/dashboardController.ts: Conditional branching logic across all data-fetching methods needs verification to ensure both code paths are correctly implemented and parameter passing is appropriate for each service.
  • dashboard/README.md: Substantial documentation changes spanning architecture, setup paths, configuration, and deployment instructions; requires validation of accuracy and clarity for dual-source workflow.
  • Integration consistency: Verify that service method signatures and data shapes are compatible across OpenSearch and Moesif code paths in the controller.

Poem

🐰 Hops of joy with data so bright,
Two sources now, configured just right!
OpenSearch meets Moesif's embrace,
Runtime switching sets a new pace,
The dashboard dances—what a delight! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete, containing only a placeholder '$subject' in the Purpose section and missing all other required template sections (Goals, Approach, User stories, Release note, Documentation, etc.). Complete the PR description by filling out all required template sections: Purpose (with actual explanation), Goals, Approach, User stories, Release note, Documentation, and other applicable sections instead of using placeholder text.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Added support for pulling data from moesif' directly aligns with the main changeset, which introduces comprehensive Moesif service integration for dashboard data retrieval.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dashboard/swift_dashboard/server/controllers/dashboardController.ts (1)

433-444: Inconsistent default timeFilter value may skew error stats when param is omitted

Here:

const timeFilter = (query.timeFilter as 'Daily' | 'Weekly' | 'Monthly' | 'All') || 'all';

'all' (lowercase) does not match the union ('All') and does not align with MoesifService.getErrorStatistics, which switches on 'Daily' / 'Weekly' and treats any other value as “monthly”. So when timeFilter is absent you effectively get monthly stats, not a true “all” period.

Suggest aligning the default with the actual semantics, e.g.:

const timeFilter =
  (query.timeFilter as 'Daily' | 'Weekly' | 'Monthly' | 'All') || 'All';

and then implementing explicit 'All' handling in both services if needed.

🧹 Nitpick comments (4)
dashboard/swift_dashboard/server/.env.example (1)

6-17: Env values are functionally fine; consider quoting to satisfy dotenv‑linter

The new variables (USE_OPENSEARCH, MOESIF_*) are consistent with how they’re read in code (string comparison / parseInt), so they’ll work as written. If you want a clean run of dotenv-linter, you can optionally:

  • Quote non-string values, e.g.:
    USE_OPENSEARCH="false"
    MOESIF_TIMEOUT="30000"
    MOESIF_MAX_RETRIES="3"
    MOESIF_RETRY_DELAY="1000"
    MOESIF_DEBUG="false"
    MOESIF_API_KEY="YOUR_MOESIF_API_KEY_HERE"
  • Reorder keys as the linter suggests.

Purely cosmetic; no runtime impact.

dashboard/README.md (2)

29-42: Add language identifiers to fenced blocks to satisfy markdownlint

markdownlint is complaining about code fences without a language at the architecture diagram and the two “Access Dashboard” URL snippets.

You can fix MD040 by tagging them as text (or another suitable language), for example:

```text
┌─────────────────────┐ ...
http://localhost:5601/app/swiftDashboard

Also applies to: 128-133, 411-416


289-304: Minor URL typo in plugin download instructions

The plain URL line includes a trailing ):

https://github.com/wso2/reference-implementation-cbpr/releases?q=Dashboard+Plugin)

This can confuse copy‑pasting. Suggest removing the extra ):

https://github.com/wso2/reference-implementation-cbpr/releases?q=Dashboard+Plugin
dashboard/swift_dashboard/server/services/moesifService.ts (1)

28-33: Caching fields are unused and invalidateCache doesn’t clear logs

You maintain cachedMessages, cachedLogs, lastCacheTime, and cacheTTL, and update them in getLogData/getAllMessages, but no method ever reads from the cache or checks TTL. invalidateCache only clears cachedMessages and lastCacheTime, not cachedLogs.

Right now this is just dead state and a misleading cache invalidation API. Consider either:

  • Implementing read‑side caching with TTL checks (and clearing both messages and logs), or
  • Removing the cache fields entirely until you need them.

Example minimal alignment if you keep caching:

  public invalidateCache() {
-    this.cachedMessages = null;
-    this.lastCacheTime = 0;
+    this.cachedMessages = null;
+    this.cachedLogs = null;
+    this.lastCacheTime = 0;
  }

and then wire cached* + cacheTTL into the read paths.

Also applies to: 371-407, 626-641, 805-808

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a2e6e9 and 80b76ed.

📒 Files selected for processing (5)
  • .gitignore (1 hunks)
  • dashboard/README.md (3 hunks)
  • dashboard/swift_dashboard/server/.env.example (1 hunks)
  • dashboard/swift_dashboard/server/controllers/dashboardController.ts (15 hunks)
  • dashboard/swift_dashboard/server/services/moesifService.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
dashboard/swift_dashboard/server/controllers/dashboardController.ts (3)
dashboard/swift_dashboard/server/controllers/index.ts (1)
  • DashboardController (19-19)
dashboard/swift_dashboard/server/types.ts (1)
  • PluginContext (46-53)
dashboard/swift_dashboard/server/services/index.ts (1)
  • OpenSearchService (19-19)
dashboard/swift_dashboard/server/services/moesifService.ts (1)
dashboard/swift_dashboard/server/types.ts (3)
  • PluginContext (46-53)
  • MessageDocument (56-72)
  • LogDocument (74-79)
🪛 dotenv-linter (4.0.0)
dashboard/swift_dashboard/server/.env.example

[warning] 6-6: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 12-12: [UnorderedKey] The MOESIF_LOG_ACTION_NAME key should go before the MOESIF_SEARCH_PATH key

(UnorderedKey)


[warning] 13-13: [UnorderedKey] The MOESIF_TIMEOUT key should go before the MOESIF_TRANSLATION_ACTION_NAME key

(UnorderedKey)


[warning] 13-13: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 14-14: [UnorderedKey] The MOESIF_MAX_RETRIES key should go before the MOESIF_SEARCH_PATH key

(UnorderedKey)


[warning] 14-14: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 15-15: [UnorderedKey] The MOESIF_RETRY_DELAY key should go before the MOESIF_SEARCH_PATH key

(UnorderedKey)


[warning] 15-15: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 16-16: [UnorderedKey] The MOESIF_DEBUG key should go before the MOESIF_LOG_ACTION_NAME key

(UnorderedKey)


[warning] 16-16: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 17-17: [UnorderedKey] The MOESIF_API_KEY key should go before the MOESIF_BASE_URL key

(UnorderedKey)


[warning] 17-17: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🪛 markdownlint-cli2 (0.18.1)
dashboard/README.md

29-29: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


128-128: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


411-411: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (2)
.gitignore (1)

26-30: LGTM!

Adding .DS_Store and .idea/ to the ignore list follows best practices—preventing macOS system artifacts and JetBrains IDE configuration files from being committed to the repository. The entries are properly formatted and consistent with the existing patterns.

dashboard/swift_dashboard/server/controllers/dashboardController.ts (1)

19-41: Data‑source toggle wiring looks consistent

The controller cleanly introduces useOpenSearch and routes all downstream calls either to OpenSearchService or MoesifService based on env.USE_OPENSEARCH === 'true'. OpenSearch is only constructed when needed, Moesif is always available as the default, and the log messages correctly reflect the chosen backend. No functional issues here.

Comment on lines +905 to +923
public async getMonthlyMessages(
direction?: string
): Promise<MessageDocument[]> {
// Get current month date range
const today = new Date();

// Start of month
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 2); // Changed from 2 to 1 to include the 1st day
startOfMonth.setHours(0, 0, 0, 0);

// End of month
const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0);
endOfMonth.setHours(23, 59, 59, 999);

// Format dates for query
const startDateStr = startOfMonth.toISOString().split('T')[0];
const endDateStr = endOfMonth.toISOString().split('T')[0];

try {
Copy link

@coderabbitai coderabbitai bot Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Monthly range starts from the 2nd, not the 1st (off‑by‑one bug)

getMonthlyMessages currently does:

const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 2); // Changed from 2 to 1 to include the 1st day

This actually excludes the 1st of the month from the query range. Since several higher‑level methods (monthly charts, recent messages with monthly period, etc.) depend on this, monthly stats will miss one day.

Fix the off‑by‑one and align the comment:

-    const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 2); // Changed from 2 to 1 to include the 1st day
+    const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); // Start from the 1st day of the month
🤖 Prompt for AI Agents
In dashboard/swift_dashboard/server/services/moesifService.ts around lines 905
to 923, the startOfMonth constructor currently uses day 2 which excludes the 1st
of the month; change the Date instantiation to use day 1 (new
Date(today.getFullYear(), today.getMonth(), 1)) so the range includes the first
day, keep the setHours(0,0,0,0) call, and update the inline comment to reflect
that the start of month is the 1st.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional and is the same for open search as well

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check OpenSearch service for monthly message implementation
fd -e ts openSearchService.ts --exec cat {}

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find any files related to OpenSearch service
fd -e ts -e js . dashboard/swift_dashboard/server/services/

# Also search for monthly message implementations
rg -n "getMonthlyMessages" --type ts -A 20

Length of output: 27497


@aka4rKO, thank you for the clarification! I've verified that both opensearchService.ts (Line 921) and moesifService.ts (Line 912) use day 2, so this is indeed consistent across both data sources.

However, I'd suggest updating the inline comment in both files since it's currently misleading. The comment says:

// Changed from 2 to 1 to include the 1st day

But the code still uses 2. Consider updating it to reflect the actual intention, for example:

// Start from the 2nd day of the month (intentional - consistent with data requirements)

This would prevent future confusion for developers reviewing the code.


✏️ Learnings added
Learnt from: aka4rKO
Repo: wso2/reference-implementation-cbpr PR: 25
File: dashboard/swift_dashboard/server/services/moesifService.ts:905-923
Timestamp: 2025-11-24T11:41:41.214Z
Learning: In the dashboard services (both MoesifService and OpenSearchService), the getMonthlyMessages() method intentionally starts from day 2 of the month (new Date(year, month, 2)) rather than day 1. This is a deliberate design decision consistent across both data source implementations.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant