Skip to content

Add Atlassian Statuspage Outage Integration#174

Merged
aadishsamir123 merged 5 commits into
mainfrom
phone+wear/enhancement/statuspage
Dec 25, 2025
Merged

Add Atlassian Statuspage Outage Integration#174
aadishsamir123 merged 5 commits into
mainfrom
phone+wear/enhancement/statuspage

Conversation

@aadishsamir123

@aadishsamir123 aadishsamir123 commented Dec 25, 2025

Copy link
Copy Markdown
Member

This pull request introduces a comprehensive Atlassian Statuspage outage integration to the app, enabling real-time outage detection, user notification via dialogs and banners, and robust error handling. It adds new models, services, and UI components for both phone/web and WearOS platforms, and ensures polling is performed efficiently and safely. The integration is reflected in the app’s startup flow, UI overlays, and documentation, with supporting configuration and testing instructions.

Statuspage Outage Integration

  • Added core Statuspage outage detection and polling service (StatuspageService), with error reporting to Sentry and session-based dialog tracking. [1] [2]
  • Introduced new data models for outages and incident updates in status_outage.dart.
  • Added configuration file for Statuspage API endpoint and polling interval (statuspage_config.dart).

User Interface Enhancements

  • Implemented a global outage banner overlay shown across all screens via MaterialApp.builder, and a fullscreen closable outage dialog (OutageDialog) that appears once per app run when an outage is active. [1] [2]
  • Integrated navigation key for global dialog handling (AppNavigation in navigation_service.dart).
  • On app startup and authentication flow, checks for active outages and displays the dialog if necessary. [1] [2]

Documentation and Testing

  • Updated contributor documentation with setup and testing instructions for the Statuspage integration, including test file locations and polling details. [1] [2]

Other Changes

  • Minor cleanup in launch configurations (removal of a phone debug entry in .vscode/launch.json).

Summary by CodeRabbit

  • New Features

    • Integrated Statuspage outage monitoring with fullscreen dialogs and a persistent banner on phone, web, and Wear OS; tapping banner opens outage details. App starts polling (~1 minute) and respects per-session dialog dismissal; errors reported.
  • Tests

    • Added unit tests validating outage parsing and empty-state defaults.
  • Chores

    • Added HTTP networking dependency and removed a multi-device debug launch configuration.

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

- Added StatuspageService for fetching and managing outage data.
- Implemented StatusOutage model to represent outage details.
- Created OutageDialog for displaying outage information.
- Added OutageBanner widget to show active outages across the app.
- Integrated polling mechanism to check for outages every minute.
- Updated WearOS screens to handle and display outage information.
- Added configuration for Statuspage API in statuspage_config.dart.
- Implemented tests for StatusOutage model and its parsing logic.
@coderabbitai

coderabbitai Bot commented Dec 25, 2025

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@aadishsamir123 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between af39d50 and 00d4be7.

📒 Files selected for processing (2)
  • lib/main.dart
  • lib/wear/screens/wear_list_groups_screen.dart
📝 Walkthrough

Walkthrough

Adds Atlassian Statuspage integration: new StatuspageService with polling, StatusOutage/IncidentUpdate models, config and global navigator key, phone/web outage banner and fullscreen dialog, WearOS outage screen and header behavior, startup initialization (poll-on-start), Sentry-wrapped error reporting, tests, and an added http dependency.

Changes

Cohort / File(s) Summary
Config & Core
lib/config/statuspage_config.dart, lib/core/navigation_service.dart, pubspec.yaml
New StatuspageConfig (baseApiUrl, pollingInterval, showInitialDialog). Global AppNavigation.navigatorKey. Adds http dependency.
Service
lib/services/platform/statuspage_service.dart
New StatuspageService: currentOutage ValueNotifier, startPolling/stopPolling, fetchCurrentOutage with JSON parsing, affected-components helper, session dialog-dismiss tracking, and Sentry error reporting.
Models
lib/models/status_outage.dart
New StatusOutage and IncidentUpdate models with fromJson and StatusOutage.none() factory.
Phone / Web UI
lib/screens/status/outage_dialog.dart, lib/widgets/status/outage_banner.dart, lib/main.dart
OutageDialog fullscreen UI, OutageBanner overlay; app wired to start polling and may show outage dialog on startup; uses AppNavigation to present dialog.
WearOS UI & Integration
lib/wear/wear_main.dart, lib/wear/screens/wear_outage_screen.dart, lib/wear/screens/wear_list_groups_screen.dart
Wear app starts polling, checks outage at init and may show WearOutageScreen; list header listens to currentOutage and can navigate to outage screen; closing marks dialog dismissed.
Tests
test/unit/services/statuspage_service_test.dart
New unit tests for IncidentUpdate.fromJson and StatusOutage.none() defaults.
Misc / IDE
.vscode/launch.json
Removed one multi-device Dart launch configuration.

Sequence Diagram(s)

sequenceDiagram
    participant App as App Startup
    participant Service as StatuspageService
    participant API as Statuspage API
    participant Sentry as Sentry
    participant UI as UI Layer

    App->>Service: startPolling()
    activate Service
    Service->>Service: immediate fetchCurrentOutage()
    Service->>API: GET /incidents or summary.json
    alt Unresolved incidents
        API-->>Service: incidents JSON
        Service->>API: GET /components (affected)
        API-->>Service: components JSON
        Service->>Service: build StatusOutage, set currentOutage
    else No incidents
        API-->>Service: summary JSON
        Service->>Service: derive indicator -> StatusOutage.none() or predictive
    end
    alt Fetch error
        Service->>Sentry: capture exception + hint
        Service->>Service: return StatusOutage.none()
    end
    Service->>UI: notify via ValueNotifier
    UI->>UI: rebuild Banner/Dialog
    Note over Service: schedule next poll (1 min)
    deactivate Service
Loading
sequenceDiagram
    participant User as User
    participant Banner as OutageBanner / Header
    participant Nav as App Navigator (AppNavigation.navigatorKey)
    participant Dialog as OutageDialog / WearOutageScreen
    participant Service as StatuspageService

    Banner->>User: renders when currentOutage.active
    User->>Banner: tap
    Banner->>Nav: push fullscreen Dialog
    activate Dialog
    User->>Dialog: tap dismiss/close
    Dialog->>Service: markDialogDismissed()
    Service->>Service: set session flag
    Dialog->>Nav: pop
    deactivate Dialog
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Atlassian Statuspage outage integration, which is the primary feature across the changeset.
Description check ✅ Passed The description is comprehensive and well-structured, covering core features, UI enhancements, documentation, and other changes with specific file references and rationale for the Statuspage integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@coderabbitai coderabbitai Bot added app:phone Related to ShopSync Phone/Web app app:wearos Related to ShopSync WearOS app enhancement New feature or request semver-minor Minor Updates labels Dec 25, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (9)
test/unit/services/statuspage_service_test.dart (1)

4-25: Consider expanding test coverage.

The existing tests are well-structured and follow the AAA pattern. However, the test coverage is limited to basic model parsing. Based on learnings, 70%+ coverage is expected for services and 80%+ for models.

Consider adding:

  • Edge cases for StatusOutage.fromJson (missing fields, malformed data)
  • Tests for StatuspageService.fetchCurrentOutage() with mocked HTTP responses
  • Error handling scenarios (network failures, API errors)

Would you like me to generate additional test cases for the StatusOutage model and StatuspageService?

lib/widgets/status/outage_banner.dart (2)

19-26: Consider removing redundant Timer.

The Timer.periodic that calls setState every minute appears redundant. The ValueListenableBuilder on line 36 already rebuilds the widget whenever StatuspageService.currentOutage changes. The Timer forces unnecessary rebuilds when there's no data change.

If the intent is to refresh relative timestamps or similar, consider a more targeted approach.

🔎 Proposed simplification
 class _OutageBannerState extends State<OutageBanner> {
   late final ValueNotifier<StatusOutage?> _notifier;
-  Timer? _timer;

   @override
   void initState() {
     super.initState();
     _notifier = StatuspageService.currentOutage;
-    _timer = Timer.periodic(const Duration(minutes: 1), (_) {
-      if (mounted) setState(() {});
-    });
   }

-  @override
-  void dispose() {
-    _timer?.cancel();
-    super.dispose();
-  }

157-175: Consider extracting shared formatting utilities.

_formatComponents is duplicated in OutageDialog (with slightly different thresholds: 3 vs 4 items). Consider extracting these to a shared utility in StatusOutage model or a dedicated formatter class for consistency.

lib/screens/status/outage_dialog.dart (1)

157-165: Consider showing local time for better user context.

Times are displayed in UTC, which is consistent but may be less intuitive for users. Consider showing local time (with timezone indicator) or adding relative time (e.g., "2 hours ago") for better UX.

lib/main.dart (1)

163-175: Consider SafeArea for the OutageBanner positioning.

The banner is positioned at top: 0, which may cause it to render under the system status bar on devices with notches or cutouts. Consider wrapping it in a SafeArea or using MediaQuery.of(context).padding.top to avoid overlap with system UI.

🔎 Proposed fix
       builder: (context, child) {
         return Stack(
           children: [
             if (child != null) child,
-            const Positioned(
+            Positioned(
               top: 0,
               left: 0,
               right: 0,
-              child: OutageBanner(),
+              child: SafeArea(
+                bottom: false,
+                child: const OutageBanner(),
+              ),
             ),
           ],
         );
       },
lib/wear/screens/wear_outage_screen.dart (2)

7-15: Unused isPredictive parameter.

The isPredictive field is declared but never referenced in the widget's build method. Either remove it if not needed, or implement the intended behavior (e.g., different UI/messaging for predictive outages).

🔎 If not needed, remove the parameter
 class WearOutageScreen extends StatefulWidget {
   final StatusOutage outage;
-  final bool isPredictive;

   const WearOutageScreen({
     super.key,
     required this.outage,
-    this.isPredictive = false,
   });

36-38: Redundant ternary expression.

Both branches of the ternary return Colors.black, making the condition pointless. Simplify to a direct assignment.

🔎 Proposed fix
             return Scaffold(
-              backgroundColor:
-                  mode == WearMode.active ? Colors.black : Colors.black,
+              backgroundColor: Colors.black,
               body: RotaryScrollbar(
lib/services/platform/statuspage_service.dart (2)

101-112: Degraded status uses DateTime.now() for startedAt.

When inferring an outage from the summary indicator (no unresolved incident), startedAt is set to DateTime.now(). This means each poll will reset the start time rather than preserving when the degradation actually began. Consider caching the first-seen timestamp or leaving it as a sentinel value.


129-138: Silent error handling in _fetchAffectedComponents.

The empty catch (_) {} block at line 136 swallows all errors without logging or Sentry capture. While this is supplementary data, consider at least logging in debug mode for diagnosability.

🔎 Proposed fix
   static Future<List<String>> _fetchAffectedComponents(Uri summaryUrl) async {
     try {
       final resp = await http.get(summaryUrl);
       if (resp.statusCode == 200) {
         final data = json.decode(resp.body) as Map<String, dynamic>;
         return _extractAffectedComponentsFromSummary(data);
       }
-    } catch (_) {}
+    } catch (e) {
+      if (kDebugMode) {
+        print('Failed to fetch affected components: $e');
+      }
+    }
     return const [];
   }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7eb49be and 9e07a12.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .github/copilot-instructions.md
  • .vscode/launch.json
  • lib/config/statuspage_config.dart
  • lib/core/navigation_service.dart
  • lib/main.dart
  • lib/models/status_outage.dart
  • lib/screens/status/outage_dialog.dart
  • lib/services/platform/statuspage_service.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/wear/wear_main.dart
  • lib/widgets/status/outage_banner.dart
  • pubspec.yaml
  • test/unit/services/statuspage_service_test.dart
💤 Files with no reviewable changes (1)
  • .vscode/launch.json
🧰 Additional context used
📓 Path-based instructions (10)
**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Wrap all service layer errors with Sentry.captureException() including contextual hints via Hint.withMap()

Files:

  • lib/config/statuspage_config.dart
  • lib/core/navigation_service.dart
  • lib/wear/wear_main.dart
  • lib/widgets/status/outage_banner.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/screens/status/outage_dialog.dart
  • lib/services/platform/statuspage_service.dart
  • lib/models/status_outage.dart
  • test/unit/services/statuspage_service_test.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/main.dart
lib/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/**/*.dart: Use FieldValue.serverTimestamp() for createdAt/updatedAt Firebase timestamp fields
Use StreamBuilder and StreamBuilder for real-time Firebase Firestore sync instead of Provider/ChangeNotifier
Use camelCase for variable names, snake_case for file names, and PascalCase for class names
Use 'completed' field name (not 'checked') and 'addedAt' timestamp (not 'createdAt') for item Firebase fields
Query recycled_items subcollection for deleted items instead of filtering items with deleted field

Files:

  • lib/config/statuspage_config.dart
  • lib/core/navigation_service.dart
  • lib/wear/wear_main.dart
  • lib/widgets/status/outage_banner.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/screens/status/outage_dialog.dart
  • lib/services/platform/statuspage_service.dart
  • lib/models/status_outage.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/main.dart
lib/wear/wear_main.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use wear_main.dart as the explicit entry point for WearOS flavor builds with --target flag

Files:

  • lib/wear/wear_main.dart
lib/wear/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use standard CircularProgressIndicator() for loading states in WearOS screens instead of CustomLoadingSpinner()

Files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/wear/screens/wear_list_groups_screen.dart
lib/widgets/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Create reusable components in lib/widgets/ directory, following naming pattern lib/widgets/{component_name}_widget.dart

Files:

  • lib/widgets/status/outage_banner.dart
lib/screens/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/screens/**/*.dart: Use CustomLoadingSpinner() from /widgets/loading_spinner.dart for phone/web loading indicators
Use SingleTickerProviderStateMixin with AnimationController for animations in screen widgets

Files:

  • lib/screens/status/outage_dialog.dart
lib/services/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/services/**/*.dart: Implement services as static utility classes without singletons or instance creation
Use Firestore queries and StreamBuilder directly for list/item CRUD operations instead of ListGroupsService
Create service files in lib/services/ directory with business logic and Firebase interactions

Files:

  • lib/services/platform/statuspage_service.dart
test/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

test/**/*.dart: Write unit tests following the AAA pattern (Arrange → Act → Assert) with descriptive test names
Mock Firebase using test_utils.dart helpers and mockito for external dependencies, avoid real Firestore calls in tests

Files:

  • test/unit/services/statuspage_service_test.dart
test/unit/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Write unit tests for services, models, and utilities with 70%+ coverage for services, 80%+ for models, and 75%+ for utilities

Files:

  • test/unit/services/statuspage_service_test.dart
lib/main.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Initialize Sentry with 100% trace/profile sample rate in main.dart for error tracking across the phone app

Files:

  • lib/main.dart
🧠 Learnings (25)
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/wear/wear_main.dart : Use wear_main.dart as the explicit entry point for WearOS flavor builds with --target flag

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/wear/screens/wear_list_groups_screen.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/wear/**/*.dart : Use standard CircularProgressIndicator() for loading states in WearOS screens instead of CustomLoadingSpinner()

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/wear/screens/wear_list_groups_screen.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/services/connectivity_service.dart : Monitor network state and show offline dialog via ConnectivityService, handle Firestore offline persistence

Applied to files:

  • lib/wear/wear_main.dart
  • lib/widgets/status/outage_banner.dart
  • lib/screens/status/outage_dialog.dart
  • .github/copilot-instructions.md
  • lib/services/platform/statuspage_service.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/*.dart : Create full-page UI screens in lib/screens/ directory following the pattern lib/screens/{screen_name}.dart

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/screens/status/outage_dialog.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/**/*.dart : Use CustomLoadingSpinner() from /widgets/loading_spinner.dart for phone/web loading indicators

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/**/*.dart : Use SingleTickerProviderStateMixin with AnimationController for animations in screen widgets

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_outage_screen.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/screens/user_insights.dart : Implement user-level insights in UserInsightsScreen accessible from home drawer, showing aggregate stats across all user's lists

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/main.dart : Initialize Sentry with 100% trace/profile sample rate in main.dart for error tracking across the phone app

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to test/widgets/**/*.dart : Write widget tests for screens and reusable components with 60%+ coverage goal, using testWidgets and WidgetTester

Applied to files:

  • lib/wear/wear_main.dart
  • .github/copilot-instructions.md
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/services/home_widget_service.dart : Use HomeWidgetService.updateWidget() to sync shopping list data to Android home widget via home_widget package

Applied to files:

  • lib/wear/wear_main.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Update copilot-instructions.md with new features, architectural patterns, and important conventions for future AI agent guidance

Applied to files:

  • .github/copilot-instructions.md
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Separate shared services and models are used across both phone and WearOS flavors despite having separate entry points

Applied to files:

  • .github/copilot-instructions.md
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/services/smart_suggestions_service.dart : Implement on-device ML via TFLite for item suggestions trained from user history, with async training and cached immediate results

Applied to files:

  • .github/copilot-instructions.md
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to test/unit/**/*.dart : Write unit tests for services, models, and utilities with 70%+ coverage for services, 80%+ for models, and 75%+ for utilities

Applied to files:

  • .github/copilot-instructions.md
  • test/unit/services/statuspage_service_test.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Implement testing alongside code; write tests before merge and ensure flutter test passes locally

Applied to files:

  • .github/copilot-instructions.md
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to test/**/*.dart : Mock Firebase using test_utils.dart helpers and mockito for external dependencies, avoid real Firestore calls in tests

Applied to files:

  • .github/copilot-instructions.md
  • test/unit/services/statuspage_service_test.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to test/**/*.dart : Write unit tests following the AAA pattern (Arrange → Act → Assert) with descriptive test names

Applied to files:

  • .github/copilot-instructions.md
  • test/unit/services/statuspage_service_test.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Mock Firebase and external dependencies in tests using test_utils.dart helpers and mockito; never make real Firestore calls in automated tests

Applied to files:

  • .github/copilot-instructions.md
  • test/unit/services/statuspage_service_test.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/**/*.dart : Implement services as static utility classes without singletons or instance creation

Applied to files:

  • lib/services/platform/statuspage_service.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/**/*.dart : Create service files in lib/services/ directory with business logic and Firebase interactions

Applied to files:

  • test/unit/services/statuspage_service_test.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/screens/list_insights.dart : Implement list-level insights in ListInsightsScreen as a navigation tab (index 1 between Items and Options) with donut chart animations

Applied to files:

  • lib/wear/screens/wear_list_groups_screen.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/**/*.dart : Use Firestore queries and StreamBuilder directly for list/item CRUD operations instead of ListGroupsService

Applied to files:

  • lib/wear/screens/wear_list_groups_screen.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/list_groups_service.dart : Use ListGroupsService for group operations (CRUD, reordering, list-group associations), not for direct list/item CRUD

Applied to files:

  • lib/wear/screens/wear_list_groups_screen.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/widgets/**/*.dart : Create reusable components in lib/widgets/ directory, following naming pattern lib/widgets/{component_name}_widget.dart

Applied to files:

  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/**/*.dart : Use StreamBuilder<QuerySnapshot> and StreamBuilder<DocumentSnapshot> for real-time Firebase Firestore sync instead of Provider/ChangeNotifier

Applied to files:

  • lib/main.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build Phone Flavor
  • GitHub Check: Build Web (WASM)
  • GitHub Check: Tests & Coverage
  • GitHub Check: Build WearOS Flavor
  • GitHub Check: Seer Code Review
  • GitHub Check: Build WearOS (Debug)
  • GitHub Check: Build Web (WASM)
  • GitHub Check: Build Phone (Debug)
🔇 Additional comments (13)
lib/core/navigation_service.dart (1)

1-6: LGTM!

Clean implementation of a global navigation key for context-free dialog navigation. This is a standard Flutter pattern for showing dialogs from services or other non-widget code.

lib/config/statuspage_config.dart (1)

1-11: LGTM!

Well-documented configuration with sensible defaults. The 1-minute polling interval is appropriate for avoiding rate limits while still providing timely outage notifications.

lib/widgets/status/outage_banner.dart (1)

47-58: LGTM with note on null context handling.

The null check on AppNavigation.navigatorKey.currentContext is good defensive coding. The silent no-op when context is null is acceptable since this edge case is rare in practice.

lib/wear/screens/wear_list_groups_screen.dart (1)

429-435: LGTM!

Clean use of a private extension to add the helper method without cluttering the main class.

lib/screens/status/outage_dialog.dart (3)

6-9: LGTM!

Well-structured StatelessWidget with clear constructor and required outage parameter.


218-269: LGTM!

Clean implementation of the updates section. Limiting to 5 updates prevents UI overflow, and the icon mapping for different statuses provides good visual cues.


271-291: LGTM!

Helper methods are clean and well-implemented. Note: _formatComponents truncates at 4 items here vs 3 in OutageBanner—this is reasonable given the dialog has more display space.

lib/main.dart (1)

66-67: LGTM! Early polling initialization.

Starting the Statuspage polling early in main() ensures outage detection begins before the UI is fully rendered, which is appropriate for this use case.

lib/wear/screens/wear_outage_screen.dart (1)

21-28: LGTM! Proper resource management and dialog dismissal.

The ScrollController is correctly disposed, and the close action properly marks the dialog as dismissed before popping the route, ensuring session state is tracked correctly.

Also applies to: 136-138

lib/models/status_outage.dart (1)

22-57: LGTM! Well-structured immutable model.

The StatusOutage class has clear field definitions, sensible defaults, and the none() factory provides a clean way to represent an inactive/empty state.

lib/services/platform/statuspage_service.dart (1)

10-19: LGTM! Well-structured static service with proper Sentry integration.

The service follows the static utility class pattern per coding guidelines. Error handling in _fetchAndUpdate and fetchCurrentOutage correctly captures exceptions with Sentry and includes contextual hints. The ValueNotifier pattern for currentOutage enables reactive UI updates.

Also applies to: 21-30, 37-52

.github/copilot-instructions.md (2)

145-160: LGTM! Comprehensive documentation for the Statuspage integration.

The documentation clearly describes the service, config, model, and UI components across phone/web and WearOS. Includes relevant file paths, polling behavior, and error handling expectations. This follows the guideline to update copilot-instructions.md with new features.


436-437: LGTM! Testing responsibilities updated.

Appropriately references the location of Statuspage-related unit tests and reminds developers to check coverage.

Comment thread lib/models/status_outage.dart
Comment thread lib/services/platform/statuspage_service.dart Outdated
Comment thread lib/services/platform/statuspage_service.dart
Comment thread lib/wear/screens/wear_list_groups_screen.dart
Comment thread lib/wear/screens/wear_list_groups_screen.dart
Comment thread lib/wear/wear_main.dart Outdated
Comment thread lib/wear/wear_main.dart
Comment thread pubspec.yaml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
lib/wear/wear_main.dart (2)

40-49: LGTM — Error handling properly implemented.

The startPolling() call is now wrapped in try-catch with Sentry error reporting and contextual hints, addressing the previous review concern. This follows the coding guidelines for service layer error wrapping.


128-151: LGTM — Outage check properly handles errors and tracks dismissal.

Both previous concerns have been addressed:

  1. Wrapped in try-catch with Sentry error reporting and contextual hints
  2. Uses .then() callback to ensure markDialogDismissed() is called when the dialog closes (via button or barrier tap)
lib/models/status_outage.dart (1)

13-20: LGTM — Defensive date parsing implemented.

The fromJson method now uses DateTime.tryParse() with a fallback to DateTime.now(), addressing the previous review concern about DateTime.parse() throwing on malformed input. This prevents crashes from unexpected API data formats.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e07a12 and 86665e1.

📒 Files selected for processing (6)
  • lib/main.dart
  • lib/models/status_outage.dart
  • lib/services/platform/statuspage_service.dart
  • lib/wear/screens/wear_list_groups_screen.dart
  • lib/wear/wear_main.dart
  • pubspec.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/wear/screens/wear_list_groups_screen.dart
  • pubspec.yaml
🧰 Additional context used
📓 Path-based instructions (6)
lib/wear/wear_main.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use wear_main.dart as the explicit entry point for WearOS flavor builds with --target flag

Files:

  • lib/wear/wear_main.dart
lib/wear/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use standard CircularProgressIndicator() for loading states in WearOS screens instead of CustomLoadingSpinner()

Files:

  • lib/wear/wear_main.dart
**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Wrap all service layer errors with Sentry.captureException() including contextual hints via Hint.withMap()

Files:

  • lib/wear/wear_main.dart
  • lib/services/platform/statuspage_service.dart
  • lib/main.dart
  • lib/models/status_outage.dart
lib/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/**/*.dart: Use FieldValue.serverTimestamp() for createdAt/updatedAt Firebase timestamp fields
Use StreamBuilder and StreamBuilder for real-time Firebase Firestore sync instead of Provider/ChangeNotifier
Use camelCase for variable names, snake_case for file names, and PascalCase for class names
Use 'completed' field name (not 'checked') and 'addedAt' timestamp (not 'createdAt') for item Firebase fields
Query recycled_items subcollection for deleted items instead of filtering items with deleted field

Files:

  • lib/wear/wear_main.dart
  • lib/services/platform/statuspage_service.dart
  • lib/main.dart
  • lib/models/status_outage.dart
lib/services/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/services/**/*.dart: Implement services as static utility classes without singletons or instance creation
Use Firestore queries and StreamBuilder directly for list/item CRUD operations instead of ListGroupsService
Create service files in lib/services/ directory with business logic and Firebase interactions

Files:

  • lib/services/platform/statuspage_service.dart
lib/main.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Initialize Sentry with 100% trace/profile sample rate in main.dart for error tracking across the phone app

Files:

  • lib/main.dart
🧠 Learnings (17)
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/wear/wear_main.dart : Use wear_main.dart as the explicit entry point for WearOS flavor builds with --target flag

Applied to files:

  • lib/wear/wear_main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/wear/**/*.dart : Use standard CircularProgressIndicator() for loading states in WearOS screens instead of CustomLoadingSpinner()

Applied to files:

  • lib/wear/wear_main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/services/connectivity_service.dart : Monitor network state and show offline dialog via ConnectivityService, handle Firestore offline persistence

Applied to files:

  • lib/wear/wear_main.dart
  • lib/services/platform/statuspage_service.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to **/*.dart : Wrap all service layer errors with Sentry.captureException() including contextual hints via Hint.withMap()

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/main.dart : Initialize Sentry with 100% trace/profile sample rate in main.dart for error tracking across the phone app

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/*.dart : Create full-page UI screens in lib/screens/ directory following the pattern lib/screens/{screen_name}.dart

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/**/*.dart : Use CustomLoadingSpinner() from /widgets/loading_spinner.dart for phone/web loading indicators

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/screens/**/*.dart : Use SingleTickerProviderStateMixin with AnimationController for animations in screen widgets

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/screens/user_insights.dart : Implement user-level insights in UserInsightsScreen accessible from home drawer, showing aggregate stats across all user's lists

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to test/widgets/**/*.dart : Write widget tests for screens and reusable components with 60%+ coverage goal, using testWidgets and WidgetTester

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/services/home_widget_service.dart : Use HomeWidgetService.updateWidget() to sync shopping list data to Android home widget via home_widget package

Applied to files:

  • lib/wear/wear_main.dart
  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/**/*.dart : Implement services as static utility classes without singletons or instance creation

Applied to files:

  • lib/services/platform/statuspage_service.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/**/*.dart : Use FieldValue.serverTimestamp() for createdAt/updatedAt Firebase timestamp fields

Applied to files:

  • lib/services/platform/statuspage_service.dart
  • lib/models/status_outage.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/services/**/*.dart : Create service files in lib/services/ directory with business logic and Firebase interactions

Applied to files:

  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/widgets/**/*.dart : Create reusable components in lib/widgets/ directory, following naming pattern lib/widgets/{component_name}_widget.dart

Applied to files:

  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.411Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.411Z
Learning: Applies to lib/**/*.dart : Use StreamBuilder<QuerySnapshot> and StreamBuilder<DocumentSnapshot> for real-time Firebase Firestore sync instead of Provider/ChangeNotifier

Applied to files:

  • lib/main.dart
📚 Learning: 2025-12-15T14:57:06.412Z
Learnt from: CR
Repo: ASDev-Official/shopsync PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-15T14:57:06.412Z
Learning: Applies to lib/**/*.dart : Use 'completed' field name (not 'checked') and 'addedAt' timestamp (not 'createdAt') for item Firebase fields

Applied to files:

  • lib/models/status_outage.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build WearOS Flavor
  • GitHub Check: Build Phone Flavor
  • GitHub Check: Tests & Coverage
  • GitHub Check: Build Web (WASM)
  • GitHub Check: Build WearOS (Debug)
  • GitHub Check: Build Phone (Debug)
  • GitHub Check: Build Web (WASM)
🔇 Additional comments (6)
lib/main.dart (1)

163-175: LGTM — Global outage banner properly integrated.

The MaterialApp.builder correctly overlays the OutageBanner at the top of all screens using a Stack layout. The null check for child is appropriate.

lib/services/platform/statuspage_service.dart (4)

10-19: LGTM — Service structure follows coding guidelines.

The service correctly implements static utility class pattern without singletons. The session-based dialog dismissal tracking using a static boolean is appropriate for this use case.

Based on coding guidelines, services should be implemented as static utility classes without singletons or instance creation.


21-35: LGTM — Polling lifecycle properly managed.

The polling implementation correctly:

  • Performs an immediate fetch before starting periodic polling
  • Cancels existing timer before creating a new one to prevent leaks
  • Provides cleanup via stopPolling()

54-146: LGTM — Robust error handling and defensive parsing.

This implementation addresses all previous review concerns:

  • HTTP requests now include 5-second timeouts (lines 62, 112) to prevent indefinite hangs
  • Uses DateTime.tryParse() (lines 76-77, 79) instead of DateTime.parse() to handle malformed timestamps
  • Logs Sentry warnings when date parsing fails (lines 82-91) with contextual hints
  • Falls back to StatusOutage.none() on all error paths

148-173: LGTM — Helper methods use safe fallback pattern.

The helper methods correctly:

  • _fetchAffectedComponents: Returns an empty list on any error, which is a safe default for component listings
  • _extractAffectedComponentsFromSummary: Performs pure data extraction with null-safe operators

The empty catch block (line 156) is acceptable here since the method returns a safe fallback value.

lib/models/status_outage.dart (1)

23-58: LGTM — Well-designed data model.

The StatusOutage class is well-structured:

  • All fields properly typed with appropriate nullable/non-nullable distinctions
  • The none() factory provides a clean way to represent "no outage" state
  • Default values for collections prevent null-related issues

Comment thread lib/main.dart Outdated
Comment thread lib/main.dart
aadishsamir123 and others added 2 commits December 25, 2025 19:17
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Comment thread lib/services/platform/statuspage_service.dart
@aadishsamir123 aadishsamir123 merged commit 4c0bdbf into main Dec 25, 2025
16 checks passed
@aadishsamir123 aadishsamir123 deleted the phone+wear/enhancement/statuspage branch December 25, 2025 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:phone Related to ShopSync Phone/Web app app:wearos Related to ShopSync WearOS app enhancement New feature or request semver-minor Minor Updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant