Skip to content

Conversation

@asithade
Copy link
Contributor

Summary

Integrate NATS messaging system to enable project slug-to-ID resolution within the Kubernetes cluster environment.

  • On-Demand Connection: NATS connects only when slug endpoint is accessed (lazy loading)
  • 🔄 Slug Resolution: Successfully converts project slugs to UUIDs via NATS request/reply
  • 🚀 No Port-Forwarding: Direct cluster DNS communication without additional setup
  • 🛡️ Error Handling: Proper handling of successful lookups and missing projects

Implementation Details

  • NATS SDK Integration: Added NATS.js dependency with lazy loading connection
  • Request/Reply Pattern: Implemented simple request/reply to lfx.projects-api.slug_to_uid subject
  • Cluster Communication: Using cluster DNS lfx-platform-nats.lfx.svc.cluster.local:4222
  • Consolidated Service: Combined duplicate slug methods into single getProjectBySlug

Files Modified

  • apps/lfx-pcc/src/server/services/nats.service.ts - New NATS service with lazy loading
  • packages/shared/src/interfaces/nats.interface.ts - NATS interfaces and enums
  • apps/lfx-pcc/src/server/services/project.service.ts - Consolidated slug resolution
  • apps/lfx-pcc/src/server/routes/projects.ts - Updated to use NATS service
  • apps/lfx-pcc/.env.example - Added NATS configuration example
  • apps/lfx-pcc/package.json & yarn.lock - NATS.js dependency

Test plan

  • Verify NATS connection logs and slug resolution functionality
  • Confirm correct project ID retrieval for valid slugs (e.g., "cncf" → UUID)
  • Test error handling for non-existent slugs (proper 404 responses)
  • Validate lazy loading behavior (connection only on slug endpoint access)
  • Ensure build and lint checks pass
  • Manual testing in cluster environment
  • Verify graceful shutdown handling

Related Issues

Resolves LFXV2-337

🤖 Generated with Claude Code

asithade and others added 10 commits August 20, 2025 15:18
Remove Claude Code subagent system configuration files and simplify
CLAUDE.md documentation to reduce complexity and maintenance overhead.

- Delete .claude/agents/angular-ui-expert.md
- Delete .claude/agents/jira-project-manager.md
- Remove subagent system section from CLAUDE.md
- Simplify commit workflow documentation

LFXV2-334

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
- Rename meeting-create component to meeting-manage for both create/edit functionality
- Add confirmation dialog for attachment deletion with proper refresh mechanism
- Fix attachment saving in edit mode to properly add new attachments to existing meetings
- Improve error handling: replace forkJoin all-or-nothing with individual attachment error handling
- Add loading state signal for attachment deletion progress tracking
- Extract reusable code to shared package for better maintainability:
  - Move constants (TOTAL_STEPS, DEFAULT_DURATION, etc.) to shared/constants/meeting.ts
  - Create validators directory with meeting-specific form validators
  - Add date/time utilities (combineDateTime, formatTo12Hour, etc.) to shared/utils
- Refactor component to use extracted utilities, reducing code duplication by 700+ lines
- Add Angular forms as peer dependency to shared package for validators
- Update routing to support both /meetings/create and /meetings/:id/edit paths
- Implement loading spinner for delete attachment button

Addresses LFXV2-286: Meeting create/edit functionality consolidation

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
Signed-off-by: Asitha de Silva <[email protected]>
- Fix critical bug in MS_IN_DAY constant calculation
  - Was incorrectly calculating milliseconds in a week (604,800,000)
  - Now correctly calculates milliseconds in a day (86,400,000)
  - Removed erroneous DAYS_IN_WEEK multiplication
- Add comprehensive JSDoc documentation to all meeting constants
  - Time calculation constants with mathematical explanations
  - Meeting configuration defaults with usage examples
  - Form validation and navigation constants
  - Access control and recurrence mapping enums
- Organize constants into logical sections with clear headers
- Validate all time arithmetic is mathematically correct
- Ensure date operations (like week addition) now work properly

This fixes potential date calculation bugs in meeting recurrence logic.

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
- Standardize file naming with consistent suffixes (.constants, .interface, .enum, .validators, .utils)
- Add comprehensive JSDoc documentation to all constants, enums, and interfaces
- Fix critical MS_IN_DAY calculation bug (was calculating weeks instead of days)
- Consolidate date and timezone utilities into date-time.utils.ts
- Update all import/export statements to maintain compatibility
- Improve code maintainability with self-documenting interfaces

Generated with [Claude Code](https://claude.ai/code)

LFXV2-286

Signed-off-by: Asitha de Silva <[email protected]>
- Add date-fns-tz dependency for proper timezone support
- Update combineDateTime to accept timezone parameter and use fromZonedTime for UTC conversion
- Replace brittle toLocaleString/new Date parsing with timezone-aware utility functions
- Add timezone utility functions: compareDateTimesInTimezone, getCurrentTimeInTimezone, isDateTimeInFutureForTimezone
- Update futureDateTimeValidator to use proper timezone handling
- Remove duplicate validator and utility functions from meeting form component
- Ensure meeting scheduling works correctly across different timezones

LFXV2-286

Signed-off-by: Asitha de Silva <[email protected]>
- Replace ad-hoc custom duration validation with shared customDurationValidator
- Add explicit time format validation using timeFormatValidator
- Add topic and agenda content validators for better input validation
- Add runtime safety check to prevent NaN duration from bypassing validation
- Ensure consistent validation patterns across all meeting form components
- Fix dependency management by removing duplicates from app package.json

LFXV2-286

Signed-off-by: Asitha de Silva <[email protected]>
- Add NATS.js SDK dependency for cluster messaging
- Implement lazy-loading NATS service with request/reply pattern
- Create consolidated getProjectBySlug method using NATS resolution
- Add NATS interfaces and configuration for lfx.projects-api.slug_to_uid subject
- Update project routes to use NATS for slug resolution
- Configure cluster DNS connection to lfx-platform-nats.lfx.svc.cluster.local:4222
- Add graceful shutdown handling for NATS connections

Resolves LFXV2-337

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Asitha de Silva <[email protected]>
Copilot AI review requested due to automatic review settings August 21, 2025 19:13
@asithade asithade requested a review from jordane as a code owner August 21, 2025 19:13
@asithade asithade requested a review from emsearcy August 21, 2025 19:13
@coderabbitai
Copy link

coderabbitai bot commented Aug 21, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Caution

Review failed

The pull request is closed.

Walkthrough

Introduces NATS-based slug-to-UID resolution and refactors project routes to a controller/service pattern. Adds NATS config/env and dependency. Updates Supabase and frontend to use project UID for recent activity. Adjusts committee wiring to internalize dependencies. Adds e2e API mocks and test-ids. Minor editor settings update.

Changes

Cohort / File(s) Summary
NATS integration
apps/lfx-pcc/.env.example, apps/lfx-pcc/package.json, apps/lfx-pcc/src/server/services/nats.service.ts, packages/shared/src/constants/api.constants.ts, packages/shared/src/interfaces/nats.interface.ts, packages/shared/src/interfaces/index.ts
Adds NATS dependency, env var, config constants, interfaces, and a NatsService with lazy connection and slug-to-UID request-reply.
Project controller/service and routes
apps/lfx-pcc/src/server/controllers/project.controller.ts, apps/lfx-pcc/src/server/services/project.service.ts, apps/lfx-pcc/src/server/routes/projects.ts
Moves project route logic to ProjectController/ProjectService; integrates NATS for slug resolution; adds GET /:uid/recent-activity; removes direct microservice proxy usage from routes.
Supabase service update
apps/lfx-pcc/src/server/services/supabase.service.ts
Renames getProjectBySlug to getProjectById and switches query from slug to uid. Import order adjusted.
Frontend recent activity by UID
apps/lfx-pcc/src/app/shared/services/activity.service.ts, apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts
Changes API path and parameter from slug to uid for recent activity retrieval.
Committee wiring simplification
apps/lfx-pcc/src/server/controllers/committee.controller.ts, apps/lfx-pcc/src/server/services/committee.service.ts, apps/lfx-pcc/src/server/routes/committees.ts
Removes injected MicroserviceProxyService; services/controllers now self-instantiate dependencies; routes adjusted accordingly.
E2E mocks and tests
apps/lfx-pcc/e2e/fixtures/mock-data/*.ts, apps/lfx-pcc/e2e/helpers/api-mock.helper.ts, apps/lfx-pcc/e2e/homepage.spec.ts, apps/lfx-pcc/e2e/project-dashboard*.spec.ts
Adds mock project data and API route mocking helper; integrates mocks into tests; refines selectors and assertions.
UI test-ids
apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html
Adds data-testids for metrics and menu items; wraps Settings text in span.
Editor settings
.vscode/settings.json
Adds spell-check dictionary entries.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Frontend
  participant API as ProjectController
  participant Svc as ProjectService
  participant NATS as NatsService
  participant Broker as NATS
  participant LFX as MicroserviceProxy (LFX_V2 /query/resources)

  User->>UI: Navigate to /projects/:slug
  UI->>API: GET /api/projects/:slug
  API->>Svc: getProjectBySlug(slug)
  Svc->>NATS: getProjectIdBySlug(slug)
  NATS->>Broker: request PROJECT_SLUG_TO_UID(slug)
  Broker-->>NATS: { projectId, exists }
  NATS-->>Svc: projectId or not found
  alt slug resolved
    Svc->>LFX: GET /query/resources?type=project&tags=projectId
    LFX-->>Svc: resource list
    Svc-->>API: Project
    API-->>UI: 200 JSON(Project)
  else not found/timeout
    Svc-->>API: throw 404 PROJECT_NOT_FOUND
    API-->>UI: 404 JSON(error)
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant UI as Frontend (ActivityService)
  participant API as Projects Route
  participant SB as SupabaseService

  User->>UI: View Project Dashboard
  UI->>API: GET /api/projects/:uid/recent-activity?limit=10
  API->>SB: getRecentActivityByProjectUid(uid, limit)
  SB-->>API: RecentActivity[]
  API-->>UI: 200 JSON(RecentActivity[])
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 57294a5 and 336cb90.

📒 Files selected for processing (8)
  • apps/lfx-pcc/src/server/controllers/committee.controller.ts (1 hunks)
  • apps/lfx-pcc/src/server/controllers/project.controller.ts (1 hunks)
  • apps/lfx-pcc/src/server/routes/committees.ts (1 hunks)
  • apps/lfx-pcc/src/server/routes/projects.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/committee.service.ts (2 hunks)
  • apps/lfx-pcc/src/server/services/nats.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/project.service.ts (1 hunks)
  • packages/shared/src/constants/api.constants.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/LFXV2-337

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Integrates NATS messaging system to enable project slug-to-ID resolution within the Kubernetes cluster environment, replacing the previous Supabase-based slug resolution approach.

  • Added NATS service with lazy connection for project slug-to-ID resolution
  • Consolidated duplicate slug methods into a unified project service layer
  • Implemented request/reply pattern for cluster DNS communication without port-forwarding

Reviewed Changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/nats.interface.ts Defines NATS interfaces and subjects for project slug resolution
packages/shared/src/interfaces/index.ts Exports NATS interfaces to shared package
apps/lfx-pcc/src/server/services/nats.service.ts New NATS service implementing lazy connection and slug-to-ID resolution
apps/lfx-pcc/src/server/services/project.service.ts New consolidated project service with NATS-based slug resolution
apps/lfx-pcc/src/server/services/supabase.service.ts Updates method signature from slug-based to ID-based lookup
apps/lfx-pcc/src/server/routes/projects.ts Refactors routes to use new project service layer
apps/lfx-pcc/package.json Adds NATS.js dependency
apps/lfx-pcc/.env.example Adds NATS configuration example

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

- Extract hardcoded NATS URL to configuration constants in nats.config.ts
- Implement thread-safe connection management with promise-based synchronization
- Fix NatsService instantiation by using dependency injection instead of per-request instances
- Add proper connection pooling and prevent race conditions during concurrent requests
- Use configuration constants for timeouts and server URLs

Performance improvements:
- Reuse single NatsService instance across all slug lookups
- Prevent multiple concurrent connection attempts with connectionPromise
- Centralized configuration management for better maintainability

Resolves architecture feedback on LFXV2-337

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Asitha de Silva <[email protected]>
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: 5

🧹 Nitpick comments (13)
apps/lfx-pcc/.env.example (1)

24-27: Add production-ready NATS options (auth/TLS/timeout) placeholders

Consider expanding the example with commented vars for secure prod setups and operational tuning. Helps avoid committing ad‑hoc secrets and clarifies contract with NatsService.

 # NATS Configuration
 # Internal k8s service DNS for NATS cluster
 NATS_URL=nats://lfx-platform-nats.lfx.svc.cluster.local:4222
+
+# Optional: Auth/TLS (uncomment in non-dev environments)
+# NATS_USER=your-user
+# NATS_PASSWORD=your-password
+# NATS_NKEY_SEED=SUxxxx...             # Prefer NKeys over user/pass when possible
+# NATS_TLS_CA=/etc/ssl/certs/ca.crt
+# NATS_TLS_CERT=/etc/ssl/certs/tls.crt
+# NATS_TLS_KEY=/etc/ssl/private/tls.key
+
+# Optional: Client behavior
+# NATS_REQUEST_TIMEOUT_MS=1500
+# NATS_RECONNECT_TIME_WAIT_MS=2000
+# NATS_MAX_RECONNECT_ATTEMPTS=120
+# NATS_NAME=lfx-pcc
packages/shared/src/interfaces/nats.interface.ts (2)

7-11: Tighten response typing to reflect “not found” cases

When exists is false, projectId can’t be a meaningful ID. Encode that in the type to prevent accidental usage.

 export interface ProjectSlugToIdResponse {
-  projectId: string;
+  // When exists is false, projectId will be null
+  projectId: string | null;
   slug: string;
   exists: boolean;
 }

Optionally, define an explicit request payload for completeness:

// Add near the response interface
export interface ProjectSlugToIdRequest {
  slug: string;
}

16-18: Minor naming consistency: Id vs Uid

Enum uses slug_to_uid while the interface is ProjectSlugToIdResponse. Consider aligning on “Uid” or “Id” across both to reduce cognitive load. Not a blocker given the subject name is dictated by the upstream service.

apps/lfx-pcc/src/server/services/supabase.service.ts (1)

83-86: Parameter naming: prefer projectUid to match query key

The method targets the uid column; naming the param accordingly improves readability without changing the API shape.

-  public async getProjectById(id: string) {
+  public async getProjectById(projectUid: string) {
     const params = {
-      uid: `eq.${id}`,
+      uid: `eq.${projectUid}`,
       limit: '1',
     };
apps/lfx-pcc/src/server/routes/projects.ts (3)

147-149: Good refactor; add safeguard on logging project_uid

The refactor to use getProjectBySlug() looks good. Minor: if typings allow, ensure project.uid is always present to avoid undefined in logs. If not guaranteed by type, guard the log field.

Apply this diff:

-        project_uid: project.uid,
+        project_uid: project?.uid,

Also applies to: 154-159


208-211: Include slug in recent-activity error logs for better traceability

The success log includes project_uid, but the error path lacks the slug context. Add slug to error logs here for parity with the /:slug route.

Apply this diff:

-    const project = await projectService.getProjectBySlug(req, projectSlug);
+    const project = await projectService.getProjectBySlug(req, projectSlug);
-      {
+      {
         error: error instanceof Error ? error.message : error,
         operation: 'fetch_project_recent_activity',
+        slug: projectSlug,
         duration,
       },

Also applies to: 229-235


17-57: Optional: centralize request-timing/log pattern

Multiple handlers duplicate the same startTime/duration pattern. Consider small helper/middleware for timing to reduce repetition and potential drift.

Also applies to: 59-116, 118-176, 178-238

apps/lfx-pcc/src/server/services/project.service.ts (3)

96-103: Distinguish “not found” from transient NATS errors

Today, NatsService maps timeouts/no-responders to exists: false, which becomes a 404 here. Consider surfacing transient conditions (timeout, no responders) as 503 Service Unavailable to avoid misdiagnosing outages as missing resources.

If you adopt this, either:

  • make NatsService throw typed errors for transient conditions and catch/translate here, or
  • extend ProjectSlugToIdResponse to include a reason flag (e.g., reason: 'NOT_FOUND' | 'TIMEOUT' | 'NO_RESPONDERS') and branch status accordingly.

26-29: Optional: factor out common query->resources mapping

getProjects and searchProjects share identical proxy + map code. Consider a private helper to reduce duplication and centralize error handling.

Also applies to: 73-76


67-72: Sanitize/limit search input to prevent expensive scans

Trim searchQuery and consider enforcing a reasonable max length (e.g., 256), possibly reject empty-after-trim. This guards backend from heavy or accidental broad scans.

Apply this diff:

-  public async searchProjects(req: Request, searchQuery: string): Promise<Project[]> {
+  public async searchProjects(req: Request, searchQuery: string): Promise<Project[]> {
+    const q = (searchQuery ?? '').trim();
+    if (!q) return [];
     const params = {
       type: 'project',
-      name: searchQuery,
+      name: q,
     };
apps/lfx-pcc/src/server/services/nats.service.ts (3)

60-62: isConnected() can be simplified and null-safe

Minor polish for readability.

Apply this diff:

-  public isConnected(): boolean {
-    return this.connection !== null && !this.connection.isClosed();
-  }
+  public isConnected(): boolean {
+    return !!this.connection && !this.connection.isClosed();
+  }

67-79: Consider closing after drain and integrating with process signals

Drain gracefully flushes and closes; you might also call close() as a fallback in finally. Also, ensure the app calls shutdown() on SIGINT/SIGTERM.

Example outside this file (in server bootstrap):

const onShutdown = async () => {
  await natsService.shutdown().catch(() => {});
  process.exit(0);
};
process.on('SIGINT', onShutdown);
process.on('SIGTERM', onShutdown);

89-99: Security: add TLS support via env to avoid plaintext in production

Defaulting to nats:// is fine for dev, but expose a way to enable TLS (e.g., NATS_URL starting with tls:// or providing tls options).

Example (outside diff scope):

const useTls = natsUrl.startsWith('tls://');
this.connectingPromise = connect({
  servers: [natsUrl],
  ...(useTls ? { tls: {} } : {}),
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9fcea72 and 11410b5.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (8)
  • apps/lfx-pcc/.env.example (1 hunks)
  • apps/lfx-pcc/package.json (1 hunks)
  • apps/lfx-pcc/src/server/routes/projects.ts (7 hunks)
  • apps/lfx-pcc/src/server/services/nats.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/project.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/supabase.service.ts (2 hunks)
  • packages/shared/src/interfaces/index.ts (1 hunks)
  • packages/shared/src/interfaces/nats.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,html,scss,css,js,mjs,cjs}

📄 CodeRabbit inference engine (CLAUDE.md)

License headers are required on all source files; run ./check-headers.sh to verify

Files:

  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Do not nest ternary expressions
Prefer TypeScript interfaces over union types for maintainability

Files:

  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all shared interfaces in the shared package under src/interfaces

Files:

  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Always use direct imports for Angular standalone components; do not use barrel exports

Files:

  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
🧠 Learnings (1)
📚 Learning: 2025-08-18T23:33:26.258Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-pcc-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-18T23:33:26.258Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all shared interfaces in the shared package under src/interfaces

Applied to files:

  • packages/shared/src/interfaces/index.ts
⏰ 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). (1)
  • GitHub Check: E2E Tests / Playwright E2E Tests
🔇 Additional comments (12)
apps/lfx-pcc/package.json (1)

42-42: NATS imports are server-only — LGTM

Verified via ripgrep that the only nats import lives in apps/lfx-pcc/src/server/services/nats.service.ts, with no occurrences in browser-targeted code. No further action needed.

packages/shared/src/interfaces/nats.interface.ts (1)

1-2: License header present—LGTM

apps/lfx-pcc/src/server/services/supabase.service.ts (1)

27-28: Import reordering and usage—LGTM

createApiError/createHttpError are used later (parseSupabaseError), and dotenv.config() is still called early.

packages/shared/src/interfaces/index.ts (1)

42-45: Barrel export for NATS interfaces—LGTM

Keeps shared types centralized and discoverable.

apps/lfx-pcc/src/server/routes/projects.ts (3)

29-29: LGTM: Delegation to ProjectService.getProjects()

Route cleanly delegates to the service; logging and error handling are consistent.


89-89: LGTM: Delegation to ProjectService.searchProjects()

Input validation for q is present; result logging looks good.


1-2: License header present

Headers meet repository policy.

apps/lfx-pcc/src/server/services/project.service.ts (3)

42-49: Good 404 shape and logging for unknown project ID

Error construction with service code and explicit 404 is clear; warning on multi-hit case below is also helpful.


1-2: License header present

Matches repository requirements.


1-118: No residual slug-based Supabase calls detected

I ran a repo-wide search for legacy slug lookups (slug_to_uid, direct /slug queries) and only found the new NATS-based resolution paths and related interfaces. All Supabase service calls (e.g. supabaseService.getRecentActivityByProject) now use project.uid, not slugs.

• NATS subjects enum (PROJECT_SLUG_TO_UID) in packages/shared/src/interfaces/nats.interface.ts
ProjectService.getProjectBySlug and its two usages in apps/lfx-pcc/src/server/routes/projects.ts (both correctly invoke NATS first)
• No occurrences of slug_to_uid or direct /slug lookups in Supabase calls

Everything looks clean—no further changes needed.

apps/lfx-pcc/src/server/services/nats.service.ts (2)

24-41: Trim-and-validate response and normalize logging

Good handling of blank IDs and trimming. Consider logging the connection status in debug when resolving to aid support.


1-2: License header present

Compliant with repository policy.

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

♻️ Duplicate comments (1)
apps/lfx-pcc/src/server/services/nats.service.ts (1)

86-111: Thread-safe lazy connection: LGTM and addresses earlier race concerns.

connectionPromise gate avoids duplicate connections under load. Nice.

🧹 Nitpick comments (16)
apps/lfx-pcc/package.json (1)

42-42: Add and Pin the NATS Dependency Thoughtfully

  • Confirmed that [email protected] is the current latest dist-tag on npm and is licensed under Apache-2.0 .
  • To limit upgrades to patch releases only, you can switch to tilde pinning ("nats": "~2.29.3"); if you’d rather allow non-breaking minor updates, keep the caret ("nats": "^2.29.3") and rely on your CI pipeline (e.g., npm audit) to catch any regressions.
  • As a final step, run npm audit (or consult the GitHub Security Advisory or Snyk) for nats to ensure there are no open vulnerabilities before merging.
apps/lfx-pcc/.env.example (1)

24-27: Expose optional NATS timeouts and auth knobs (commented) for ops

Good to include NATS_URL. Consider adding commented overrides for timeouts and credentials to make cluster tuning and secured deployments easier. Also clarify TLS vs non-TLS.

Apply this diff:

 # NATS Configuration
 # Internal k8s service DNS for NATS cluster
 NATS_URL=nats://lfx-platform-nats.lfx.svc.cluster.local:4222
+
+# Optional: override defaults from NATS_CONFIG (milliseconds)
+# NATS_CONNECTION_TIMEOUT_MS=5000
+# NATS_REQUEST_TIMEOUT_MS=5000
+
+# Optional: authentication (enable in NatsService/config before use)
+# NATS_USER=
+# NATS_PASSWORD=
+# NATS_NKEY_SEED= # e.g., "SU..."; prefer NKEY/JWT over user/pass in production
+
+# Note: use tls:// for TLS-enabled clusters and configure certs accordingly
+# e.g., NATS_URL=tls://lfx-platform-nats.lfx.svc.cluster.local:4222
packages/shared/src/interfaces/nats.interface.ts (1)

1-18: Align response naming with existing UID conventions and future-proof payload

Interface and enum look good. To reduce cognitive load across code where we use “uid” consistently (e.g., Supabase queries), consider renaming projectIdprojectUid. Optionally include an optional correlationId to help trace request/reply flows.

Apply this diff:

 export interface ProjectSlugToIdResponse {
-  projectId: string;
+  projectUid: string;
   slug: string;
   exists: boolean;
+  // Optional correlation identifier for tracing request/reply
+  correlationId?: string;
 }

Follow-up: if you adopt this, I can generate a codemod or PR-wide patch to update all references in NatsService and ProjectService. Want me to proceed?

apps/lfx-pcc/src/server/services/supabase.service.ts (1)

105-109: Count lookups can fail the whole request; align with list behavior

In getProjects you default counts to 0 on failures. Here, a transient failure in either HEAD request throws and prevents returning the project. Consider mirroring the resilient pattern.

Apply this diff:

-      const [committeeCount, meetingCount] = await Promise.all([this.getCommitteeCountByProjectId(project.uid), this.getMeetingCountByProjectId(project.uid)]);
+      const [committeeCount, meetingCount] = await Promise.all([
+        this.getCommitteeCountByProjectId(project.uid).catch(() => 0),
+        this.getMeetingCountByProjectId(project.uid).catch(() => 0),
+      ]);
apps/lfx-pcc/src/server/config/nats.config.ts (1)

11-21: Consider making timeouts environment-overridable (non-breaking default).

Small QoL improvement for ops without touching code; defaults remain 5000ms.

Apply this diff if you want env overrides:

 export const NATS_CONFIG = {
   /**
    * Default NATS server URL for Kubernetes cluster
    */
   DEFAULT_SERVER_URL: 'nats://lfx-platform-nats.lfx.svc.cluster.local:4222',

   /**
    * Connection timeout in milliseconds
    */
-  CONNECTION_TIMEOUT: 5000,
+  CONNECTION_TIMEOUT: Number.parseInt(process.env['NATS_CONNECTION_TIMEOUT_MS'] || '5000', 10),

   /**
    * Request timeout in milliseconds
    */
-  REQUEST_TIMEOUT: 5000,
+  REQUEST_TIMEOUT: Number.parseInt(process.env['NATS_REQUEST_TIMEOUT_MS'] || '5000', 10),
 } as const;
apps/lfx-pcc/src/server/routes/projects.ts (5)

16-18: Good DI at module scope; ensure graceful shutdown wires NATS drain.

Instantiating NatsService once is correct for reuse. Make sure the server bootstrap calls natsService.shutdown() on SIGINT/SIGTERM to avoid dropped in-flight requests.

Do you want me to add a minimal shutdown hook in the server entrypoint?


74-90: Treat whitespace-only queries as invalid.

q=' ' passes current checks. Trim and validate min length to avoid pointless downstream requests.

-  if (!q || typeof q !== 'string') {
+  if (!q || typeof q !== 'string' || q.trim().length === 0) {

133-147: Redundant param check for /:slug route.

Express won't hit this handler without slug. Safe to keep, but it’s unreachable in practice.


185-191: Log the actual slug for recent-activity for parity with other endpoints.

Elsewhere you log slug. Consistency helps debugging/correlation.

-  has_project_slug: !!projectSlug,
+  slug: projectSlug,

210-214: Recent-activity: sanitize/pin query params (optional).

If req.query flows to Supabase unrestricted, consider whitelisting supported params (e.g., limit, since) to avoid accidental fan-out or unexpected filters.

I can add a small helper to pick/validate keys if you’d like.

apps/lfx-pcc/src/server/services/nats.service.ts (3)

21-35: Normalize slug before request (trim/lowercase) to reduce 404s due to case/whitespace drift.

If the responder is case-insensitive, normalizing here prevents cache misses and inconsistent lookups.

Is slug resolution case-sensitive in lfx.projects-api.slug_to_uid? If not, we should normalize.

-  public async getProjectIdBySlug(slug: string): Promise<ProjectSlugToIdResponse> {
+  public async getProjectIdBySlug(slug: string): Promise<ProjectSlugToIdResponse> {
+    const normalizedSlug = slug.trim().toLowerCase();
     const connection = await this.ensureConnection();

     try {
-      const response = await connection.request(NatsSubjects.PROJECT_SLUG_TO_UID, this.codec.encode(slug), { timeout: NATS_CONFIG.REQUEST_TIMEOUT });
+      const response = await connection.request(
+        NatsSubjects.PROJECT_SLUG_TO_UID,
+        this.codec.encode(normalizedSlug),
+        { timeout: NATS_CONFIG.REQUEST_TIMEOUT }
+      );

116-129: Harden connection options and observability.

Add a client name and reconnection policy for better tracing and resilience.

-      const connection = await connect({
-        servers: [natsUrl],
-        timeout: NATS_CONFIG.CONNECTION_TIMEOUT,
-      });
+      const connection = await connect({
+        servers: [natsUrl],
+        timeout: NATS_CONFIG.CONNECTION_TIMEOUT,
+        name: process.env['NATS_CLIENT_NAME'] || `lfx-pcc:${process.env['HOSTNAME'] || 'unknown'}`,
+        maxReconnectAttempts: -1,         // keep trying
+        reconnectTimeWait: 2000,          // 2s backoff
+        pingInterval: 20000,              // keep-alive
+      });

If desired, we can also log for await (const s of connection.status()) events.


69-81: Shutdown: clear any in-flight promise and force-close on drain failure.

Edge case: if shutdown races with a new connect, ensure future calls don’t await a stale promise.

   public async shutdown(): Promise<void> {
     if (this.connection && !this.connection.isClosed()) {
       serverLogger.info('Shutting down NATS connection');

       try {
         await this.connection.drain();
         serverLogger.info('NATS connection closed successfully');
       } catch (error) {
         serverLogger.error({ error: error instanceof Error ? error.message : error }, 'Error during NATS shutdown');
+        try {
+          await this.connection.close();
+        } catch (_) {/* noop */}
       }
     }
-    this.connection = null;
+    this.connection = null;
+    this.connectionPromise = null;
   }
apps/lfx-pcc/src/server/services/project.service.ts (3)

43-65: 404 handling is correct; align service identifier for consistency.

You use 'lfx-v2' here and 'nats' elsewhere. Consider standardizing service identifiers for logs/errors (e.g., 'lfx-v2-service').

-        service: 'lfx-v2',
+        service: 'lfx-v2-service',

70-79: Search: trim and validate the query to reduce noisy backend calls.

Mirror the router’s stricter validation inside the service layer for defense in depth.

-  public async searchProjects(req: Request, searchQuery: string): Promise<Project[]> {
+  public async searchProjects(req: Request, searchQuery: string): Promise<Project[]> {
+    const q = searchQuery.trim();
+    if (!q) {
+      return [];
+    }
     const params = {
       type: 'project',
-      name: searchQuery,
+      name: q,
     };

85-118: Slug flow is clean; consider adding the slug to the 404 for better UX/observability.

Returning which slug wasn’t found helps both users and logs.

-      throw createApiError({
-        message: 'Project not found',
+      throw createApiError({
+        message: `Project not found for slug "${projectSlug}"`,
         status: 404,
         code: 'PROJECT_NOT_FOUND',
         service: 'nats',
       });

Also, optional: small in-memory cache for slug→ID with short TTL can reduce NATS load.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9fcea72 and f6471fe.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • apps/lfx-pcc/.env.example (1 hunks)
  • apps/lfx-pcc/package.json (1 hunks)
  • apps/lfx-pcc/src/server/config/nats.config.ts (1 hunks)
  • apps/lfx-pcc/src/server/routes/projects.ts (7 hunks)
  • apps/lfx-pcc/src/server/services/nats.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/project.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/services/supabase.service.ts (2 hunks)
  • packages/shared/src/interfaces/index.ts (1 hunks)
  • packages/shared/src/interfaces/nats.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,html,scss,css,js,mjs,cjs}

📄 CodeRabbit inference engine (CLAUDE.md)

License headers are required on all source files; run ./check-headers.sh to verify

Files:

  • apps/lfx-pcc/src/server/config/nats.config.ts
  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Always use direct imports for Angular standalone components; do not use barrel exports

Files:

  • apps/lfx-pcc/src/server/config/nats.config.ts
  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Do not nest ternary expressions
Prefer TypeScript interfaces over union types for maintainability

Files:

  • apps/lfx-pcc/src/server/config/nats.config.ts
  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/server/services/project.service.ts
  • apps/lfx-pcc/src/server/services/nats.service.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all shared interfaces in the shared package under src/interfaces

Files:

  • packages/shared/src/interfaces/nats.interface.ts
  • packages/shared/src/interfaces/index.ts
🧠 Learnings (1)
📚 Learning: 2025-08-18T23:33:26.258Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-pcc-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-18T23:33:26.258Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all shared interfaces in the shared package under src/interfaces

Applied to files:

  • packages/shared/src/interfaces/index.ts
🧬 Code graph analysis (1)
apps/lfx-pcc/src/server/services/project.service.ts (4)
apps/lfx-pcc/src/server/services/microservice-proxy.service.ts (1)
  • MicroserviceProxyService (12-205)
packages/shared/src/interfaces/project.interface.ts (1)
  • Project (54-101)
packages/shared/src/interfaces/api.interface.ts (1)
  • QueryServiceResponse (106-109)
apps/lfx-pcc/src/server/utils/api-error.ts (1)
  • createApiError (6-39)
⏰ 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). (1)
  • GitHub Check: E2E Tests / Playwright E2E Tests
🔇 Additional comments (6)
apps/lfx-pcc/src/server/services/supabase.service.ts (2)

27-28: Import reordering — LGTM

The utilities are used in parseSupabaseError; placement is fine.


83-86: No lingering supabaseService.getProjectBySlug calls; rename is complete

I ran the provided search for getProjectBySlug( and confirmed that:

  • All hits are in
    • apps/lfx-pcc/src/server/services/project.service.ts (lines 85–87)
    • apps/lfx-pcc/src/server/routes/projects.ts (lines 150–152 and 209–213)

    These refer to the projectService’s slug‐resolution method, not the supabaseService method you renamed.

  • There are zero references to supabaseService.getProjectBySlug anywhere in the repo.

The change in supabase.service.ts to getProjectById(id: string) is therefore fully self-contained and has no remaining call sites to update.

packages/shared/src/interfaces/index.ts (1)

42-44: Re-export NATS interfaces — compliant with shared interfaces guideline

This aligns with “Place all shared interfaces in the shared package under src/interfaces”. No issues.

apps/lfx-pcc/src/server/config/nats.config.ts (1)

7-22: Config constants look solid and aligned with the PR goals.

Readonly object with sensible defaults and clear docs. Good separation from service logic.

apps/lfx-pcc/src/server/services/project.service.ts (2)

23-32: Project listing via proxy: LGTM.

Clear parameterization and mapping of resources[].data.


29-31: No unintended overrides in DEFAULT_QUERY_PARAMS

Verification confirms that DEFAULT_QUERY_PARAMS only includes the API version key (v: '1') and does not define type, uid, or name, so caller-supplied parameters for those fields cannot be overwritten by defaults.

• DEFAULT_QUERY_PARAMS defined in packages/shared/src/constants/api.constants.ts (lines 12–15):

export const DEFAULT_QUERY_PARAMS: Record<string, string> = {
  /** API version parameter */
  v: '1',
};

• Merging in apps/lfx-pcc/src/server/services/microservice-proxy.service.ts safely applies defaults without risking override of type, uid, or name.

No further changes are needed here.

@github-actions
Copy link

github-actions bot commented Aug 21, 2025

✅ E2E Tests Passed

Browser: chromium
Status: passed

All E2E tests passed successfully.

Test Configuration

- Create organized mock data structure for projects in e2e/fixtures/mock-data/
- Add ApiMockHelper class to intercept /api/projects/:slug endpoint
- Update project-dashboard.spec.ts and project-dashboard-robust.spec.ts to use mocks
- Mock data includes ASWF, CNCF, and Kubernetes projects for testing
- Prevents test failures when NATS server is unavailable in test environment

🤖 Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
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: 0

♻️ Duplicate comments (1)
apps/lfx-pcc/src/server/routes/projects.ts (1)

8-18: Good: single NatsService instance injected into ProjectService

This addresses the earlier concern about per-request NATS connections and enables graceful reuse and coordinated shutdown.

🧹 Nitpick comments (19)
apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html (4)

46-50: Adhere to data-testid naming convention ([section]-[component]-[element]) for metrics

The added data-testid values ("metric-label", "metric-value") don't follow the repo convention. Consider renaming to something like "project-layout-metrics-label" and "project-layout-metrics-value". If existing e2e tests don’t rely on these exact values yet, update now; otherwise, schedule a coordinated test update.

If tests already reference these, let’s plan a quick follow-up to migrate selectors.

Example diff (if safe to change now):

-  <div class="flex items-center gap-2 mb-1" data-testid="metric-label">
+  <div class="flex items-center gap-2 mb-1" data-testid="project-layout-metrics-label">
...
-  <div class="text-2xl font-normal text-gray-900 font-display" data-testid="metric-value">{{ metric.value }}</div>
+  <div class="text-2xl font-normal text-gray-900 font-display" data-testid="project-layout-metrics-value">{{ metric.value }}</div>

65-66: Make menu item test IDs unique and convention-aligned

Using the same data-testid="menu-item" for all entries hinders precise targeting and doesn't follow the naming scheme. Prefer a dynamic, unique, and convention-aligned value per item (e.g., include the label).

Note: This will require updating e2e selectors if they currently depend on "menu-item".

Proposed change:

-  data-testid="menu-item"
+  [attr.data-testid]="'project-layout-nav-menu-item-' + (menu.label?.toLowerCase().replace(/\s+/g, '-') || 'unnamed')"

74-82: Use [routerLink] binding instead of string interpolation for Settings (mobile)

Property binding avoids brittle string concatenation and ensures proper URL encoding.

-  routerLink="/project/{{ projectSlug() }}/settings"
+  [routerLink]="['/project', projectSlug(), 'settings']"

Optionally align the test id with the convention when you update tests:

-  data-testid="mobile-menu-item"
+  data-testid="project-layout-nav-mobile-menu-item"

86-94: Use [routerLink] binding for Settings (desktop) and consider unique test id

Mirror the mobile change and consider a unique, convention-compliant test id to distinguish Settings from other menu items.

-  routerLink="/project/{{ projectSlug() }}/settings"
+  [routerLink]="['/project', projectSlug(), 'settings']"

Optionally (coordinated with tests):

-  data-testid="menu-item"
+  data-testid="project-layout-nav-settings"
apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts (4)

32-32: Use deterministic timestamps to avoid flaky e2e comparisons

new Date().toISOString() introduces time variance across runs. Prefer a fixed ISO for stability.

-    updated_at: new Date().toISOString(),
+    updated_at: '2025-01-01T00:00:00.000Z',

Repeat for other entries below.


58-58: Same as above: replace runtime timestamp with a fixed ISO string

Keeps snapshots and order-dependent tests stable.

-    updated_at: new Date().toISOString(),
+    updated_at: '2025-01-01T00:00:00.000Z',

83-83: Same as above: replace runtime timestamp with fixed value

Consistency across mock entries.

-    updated_at: new Date().toISOString(),
+    updated_at: '2025-01-01T00:00:00.000Z',

10-10: Use satisfies and freeze mockProjects to enforce typings and guard against mutations

We’ve confirmed the repo is on TypeScript 5.8.3—well above the 4.9 minimum—so the satisfies operator is available and safe to use.

Locations to update:

  • File: apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
    Line: 10 (the declaration of mockProjects)

Proposed diff:

-export const mockProjects: Record<string, Project> = {
+export const mockProjects satisfies Record<string, Project> = {
   /* …mock data… */
};
+Object.freeze(mockProjects);

Benefits:

  • satisfies Record<string, Project> gives you compile-time guarantees that each entry matches the Project shape without widening the inferred type.
  • Object.freeze at runtime prevents accidental mutations across tests, making them more reliable.
apps/lfx-pcc/src/server/routes/projects.ts (3)

31-33: Passing raw req.query downstream — consider whitelisting and normalization

Forwarding query params directly can allow unexpected keys/values to leak to the backend. Consider whitelisting allowed keys (e.g., type, name, limit, page) and normalizing types.

Example pattern:

const { name, page, limit } = req.query;
const safeQuery = {
  ...(name ? { name: String(name) } : {}),
  ...(page ? { page: Number(page) } : {}),
  ...(limit ? { limit: Math.min(Number(limit), 100) } : {}),
};
const projects = await projectService.getProjects(req, safeQuery);

180-210: Validate and clamp limit for recent activity; keep response shape consistent

Currently, any limit in req.query is passed to Supabase. Consider clamping to a reasonable max (e.g., 100) and coercing to a number. Optionally return 400 for invalid limit values.

-  const recentActivity = await supabaseService.getRecentActivityByProject(projectUid, req.query as Record<string, any>);
+  const rawLimit = (req.query?.limit as string | undefined) ?? undefined;
+  const limit = rawLimit ? Math.min(Math.max(parseInt(rawLimit, 10) || 10, 1), 100) : undefined;
+  const recentActivity = await supabaseService.getRecentActivityByProject(projectUid, { ...(limit ? { limit } : {}) });

12-18: Wire NATS graceful shutdown into app lifecycle

Since NatsService is instantiated at module scope, ensure it’s drained on process shutdown (SIGINT/SIGTERM) from the app's bootstrap (e.g., server.ts), not within the router module.

Example (in server bootstrap):

process.on('SIGINT', async () => {
  await natsService.shutdown();
  process.exit(0);
});
process.on('SIGTERM', async () => {
  await natsService.shutdown();
  process.exit(0);
});

If you’d like, I can propose a small patch to the server entrypoint once you point me to the file exporting/creating the Express app.

apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts (2)

271-273: Remove duplicate assertion for hidden search bar (mobile test)

The same “search hidden” check is performed twice in this test; keep one to reduce noise and runtime.

-      // Search bar should be hidden on mobile (responsive design)
-      await expect(page.locator('[data-testid="header-search-autocomplete"]')).toBeHidden();

86-92: Icon selector fragility: prefer data-testid over FontAwesome class names

Relying on FA class names (e.g., fa-calendar-clock) is brittle during icon pack upgrades or theme tweaks. Consider adding stable data-testid hooks to the icon containers and assert against those instead.

apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (2)

19-33: Match only /api/projects/:slug and harden slug parsing

Current pattern also matches nested paths (e.g., recent-activity) and parsing fails with trailing slashes. Narrow the route and parse via URL to avoid edge cases. Gate logs to keep CI output clean.

-    await page.route('**/api/projects/*', async (route) => {
-      const url = route.request().url();
-
-      // Skip other endpoints - only handle direct slug requests
-      if (url.includes('/search') || url.includes('/recent-activity')) {
-        await route.continue();
-        return;
-      }
-
-      const pathSegments = url.split('/');
-      const slug = pathSegments[pathSegments.length - 1].split('?')[0]; // Remove query params
-
-      console.log(`[Mock] Intercepting project request for slug: "${slug}"`);
+    await page.route(/\/api\/projects\/[^/]+(?:\?.*)?$/, async (route) => {
+      const url = route.request().url();
+      const pathname = new URL(url).pathname.replace(/\/$/, '');
+      const slug = pathname.split('/').pop()!;
+
+      if (process.env.PW_DEBUG) {
+        console.info(`[Mock] Intercepting project request for slug: "${slug}"`);
+      }

36-44: Add no-store to mocked responses to avoid caching bleed-over across tests

Helps prevent subtle flakiness when Playwright/browser caches prior fulfillments.

       if (!project) {
         await route.fulfill({
           status: 404,
           contentType: 'application/json',
+          headers: { 'cache-control': 'no-store' },
           body: JSON.stringify({
             error: 'Project not found',
             code: 'PROJECT_NOT_FOUND',
           }),
         });
         return;
       }
 
       await route.fulfill({
         status: 200,
         contentType: 'application/json',
+        headers: { 'cache-control': 'no-store' },
         body: JSON.stringify(project),
       });

Also applies to: 47-51

apps/lfx-pcc/e2e/project-dashboard.spec.ts (2)

75-82: Tame noisy console output in CI

Keep the diagnostic dump, but guard it behind PW_DEBUG to avoid cluttering logs.

-      console.log(await page.getByTestId('menu-item').allInnerTexts());
+      if (process.env.PW_DEBUG) {
+        console.info(await page.getByTestId('menu-item').allInnerTexts());
+      }

242-248: Future-proof the year in footer assertion

Avoid a hard-coded year to prevent annual breakage.

-      await expect(page.getByText(/Copyright © 2025 The Linux Foundation/)).toBeVisible();
+      await expect(page.getByText(/Copyright © \d{4} The Linux Foundation/)).toBeVisible();
apps/lfx-pcc/e2e/homepage.spec.ts (2)

88-91: Unify the accessible-name selector for the hero search input

Other specs use the full aria-label; these lines use a truncated string that relies on exact matching and may flake. Align to the full, stable name.

-    const searchInput = page.getByRole('textbox', { name: 'Search projects, committees,' });
+    const searchInput = page.getByRole('textbox', { name: 'Search projects, committees, meetings, or mailing lists...' });

Also applies to: 129-131, 159-161, 241-243


249-250: Remove generator footer comment

Keep specs tool-agnostic to reduce noise in diffs and avoid implying a required toolchain.

-// Generated with [Claude Code](https://claude.ai/code)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f6471fe and 1715d4c.

📒 Files selected for processing (11)
  • .vscode/settings.json (1 hunks)
  • apps/lfx-pcc/e2e/fixtures/mock-data/index.ts (1 hunks)
  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts (1 hunks)
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (1 hunks)
  • apps/lfx-pcc/e2e/homepage.spec.ts (5 hunks)
  • apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts (1 hunks)
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts (2 hunks)
  • apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html (4 hunks)
  • apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/shared/services/activity.service.ts (1 hunks)
  • apps/lfx-pcc/src/server/routes/projects.ts (7 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .vscode/settings.json
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,html,scss,css,js,mjs,cjs}

📄 CodeRabbit inference engine (CLAUDE.md)

License headers are required on all source files; run ./check-headers.sh to verify

Files:

  • apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts
  • apps/lfx-pcc/e2e/fixtures/mock-data/index.ts
  • apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts
  • apps/lfx-pcc/src/app/shared/services/activity.service.ts
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts
  • apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html
  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
  • apps/lfx-pcc/e2e/homepage.spec.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
**/*-robust.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Structural E2E tests must use the -robust.spec.ts filename suffix

Files:

  • apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Do not nest ternary expressions
Prefer TypeScript interfaces over union types for maintainability

Files:

  • apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts
  • apps/lfx-pcc/e2e/fixtures/mock-data/index.ts
  • apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts
  • apps/lfx-pcc/src/app/shared/services/activity.service.ts
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts
  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
  • apps/lfx-pcc/e2e/homepage.spec.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Always use direct imports for Angular standalone components; do not use barrel exports

Files:

  • apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts
  • apps/lfx-pcc/src/app/shared/services/activity.service.ts
  • apps/lfx-pcc/src/server/routes/projects.ts
apps/lfx-pcc/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.html: Always add data-testid attributes when creating new components for reliable test targeting
Use data-testid naming convention: [section]-[component]-[element]

Files:

  • apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html
🧠 Learnings (3)
📚 Learning: 2025-08-18T23:33:26.258Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-pcc-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-18T23:33:26.258Z
Learning: Applies to **/*-robust.spec.ts : Structural E2E tests must use the -robust.spec.ts filename suffix

Applied to files:

  • apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts
📚 Learning: 2025-08-18T23:33:26.258Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-pcc-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-18T23:33:26.258Z
Learning: Applies to apps/lfx-pcc/src/**/*.html : Use data-testid naming convention: [section]-[component]-[element]

Applied to files:

  • apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html
📚 Learning: 2025-08-18T23:33:26.258Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-pcc-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-18T23:33:26.258Z
Learning: Applies to apps/lfx-pcc/src/**/*.html : Always add data-testid attributes when creating new components for reliable test targeting

Applied to files:

  • apps/lfx-pcc/src/app/layouts/project-layout/project-layout.component.html
🧬 Code graph analysis (2)
apps/lfx-pcc/src/app/shared/services/activity.service.ts (1)
packages/shared/src/interfaces/activity.interface.ts (1)
  • RecentActivity (14-29)
apps/lfx-pcc/src/server/routes/projects.ts (4)
apps/lfx-pcc/src/server/services/supabase.service.ts (1)
  • SupabaseService (31-1277)
apps/lfx-pcc/src/server/services/microservice-proxy.service.ts (1)
  • MicroserviceProxyService (12-205)
apps/lfx-pcc/src/server/services/nats.service.ts (1)
  • NatsService (10-141)
apps/lfx-pcc/src/server/services/project.service.ts (1)
  • ProjectService (14-119)
⏰ 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). (1)
  • GitHub Check: Code Quality Checks
🔇 Additional comments (7)
apps/lfx-pcc/src/app/shared/services/activity.service.ts (1)

18-26: Explicit limit handling and slug usage check

Switching to projectUid aligns with the server route. One small edge-case: if limit is 0 or negative, the current code omits the limit param (defaulting on the server, likely to 10), which may surprise callers. Consider making the check explicit:

- if (limit) {
+ if (typeof limit === 'number' && limit > 0) {
     params = params.set('limit', limit.toString());
   }

I ran a search for any calls passing project.slug into getRecentActivitiesByProject and found none. Please manually verify that no consumers still invoke this method with a slug to ensure consistency.

apps/lfx-pcc/src/app/modules/project/dashboard/project-dashboard/project.component.ts (1)

178-182: Ignore guard change — the slug check intentionally gates until the project is loaded

The existing code guards on project?.slug to delay the API call until the route-derived slug has been resolved and the full Project object (including its uid) is available. Switching the guard to project?.uid would be functionally equivalent in practice but obscures the intent: we’re waiting for the slug-based lookup to complete before fetching activities. There is no scenario in which project.uid exists while project.slug is missing, since the service populates both together when loading by slug.

Likely an incorrect or invalid review comment.

apps/lfx-pcc/src/server/routes/projects.ts (1)

149-157: Slug→UID flow via ProjectService + NATS looks solid; ensure NATS failures map to meaningful API errors

ProjectService.getProjectBySlug already translates "not found" to a 404. Double-check that unexpected NATS errors (non-timeout) are surfaced as 5xx and logged with sufficient context. No code change required here; FYI only.

apps/lfx-pcc/e2e/project-dashboard-robust.spec.ts (1)

6-12: Good call: set up slug mock before navigation

Early mocking keeps slug-driven flows deterministic across runs. Import + beforeEach placement looks solid.

apps/lfx-pcc/e2e/fixtures/mock-data/index.ts (1)

1-10: LGTM: simple, licensed barrel export

License header is present; the barrel keeps imports clean for tests/helpers.

apps/lfx-pcc/e2e/project-dashboard.spec.ts (1)

6-12: Slug mock setup is correctly placed

Import + beforeEach installation ensures all tests run against deterministic project data.

apps/lfx-pcc/e2e/homepage.spec.ts (1)

117-119: Nice: targeted slug mock only where needed

Adding the mock just in tests that navigate into project detail keeps unrelated tests unaffected and fast.

Also applies to: 152-154, 178-180

- Update getProjectById to use tags parameter for project ID lookup
- Ensures proper project resolution after NATS slug-to-ID conversion

🤖 Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
Controllers and services now initialize their own dependencies internally for cleaner architecture and simplified instantiation.

🤖 Generated with [Claude Code](https://claude.ai/code)

LFXV2-337

Signed-off-by: Asitha de Silva <[email protected]>
Move NATS configuration constants from app-specific config to shared package for better reusability and centralized configuration management.

🤖 Generated with [Claude Code](https://claude.ai/code)

LFXV2-337

Signed-off-by: Asitha de Silva <[email protected]>
@asithade asithade merged commit 47e48ec into main Aug 21, 2025
5 of 6 checks passed
@asithade asithade deleted the feat/LFXV2-337 branch August 21, 2025 22:11
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.

3 participants